У меня возникают проблемы с производительностью, когда я использую MemSQL в качестве постоянного хранилища для Quartz Scheduler.Кто-нибудь имеет опыт с этим, пожалуйста?
Я создал пример проекта - здесь: https://github.com/chapcz/quartz-memsql
Мне пришлось подготовить собственный класс семафора для блокировки планировщика (MemsqlSemaphore).
В основном классе должно быть сгенерировано X заданий, которые я хочу запускать каждые 5 секунд.Я думаю, что выполнение около 500 заданий должно быть в порядке, но планировщик вывода из логгера запускает единицы заданий в секунду (1-2).
Конфигурация планировщика
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.scheduler.instanceId = AUTO
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.threadCount = 30
org.quartz.scheduler.batchTriggerAcquisitionMaxCount = 25
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = DS
org.quartz.jobStore.misfireThreshold = 10000
org.quartz.jobStore.maxMisfiresToHandleAtATime = 100
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 1000
org.quartz.jobStore.lockHandler.class = cz.chap.quartz.MemsqlSemaphore
#============================================================================
# Configure Datasources
#============================================================================
org.quartz.dataSource.DS.driver = org.mariadb.jdbc.Driver
org.quartz.dataSource.DS.URL = jdbc:mysql://memsql.example.com:3306/quartz_test
org.quartz.dataSource.DS.user = root
org.quartz.dataSource.DS.password = secret_password
org.quartz.dataSource.DS.maxConnections = 200
org.quartz.dataSource.DS.provider = hikaricp
Реализация семафора: таблица QRTZ_LOCKS была расширена столбцом времени блокировки (без этого обновления возвращено 0 для существующей пары LOCK / SCHED) ... вдохновлено UpdateLockRowSemaphore
import org.quartz.impl.jdbcjobstore.DBSemaphore;
import org.quartz.impl.jdbcjobstore.LockException;
import org.quartz.impl.jdbcjobstore.Util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class MemsqlSemaphore extends DBSemaphore {
private static final int RETRY_COUNT = 1;
private static final String COL_LOCK_TIME = "LOCK_TIME";
private static final String INSERT_UPDATE = "INSERT INTO " + TABLE_PREFIX_SUBST + TABLE_LOCKS
+ " ( " + COL_LOCK_NAME + "," + COL_SCHEDULER_NAME + ") "
+ "VALUES (? , " + SCHED_NAME_SUBST + ") ON DUPLICATE KEY UPDATE `" + COL_LOCK_TIME + "` = ?";
public MemsqlSemaphore() {
super(DEFAULT_TABLE_PREFIX, null, INSERT_UPDATE, "SELECT 1");
}
/**
* Execute the SQL select for update that will lock the proper database row.
*/
@Override
protected void executeSQL(Connection conn, final String lockName, final String expandedSQL, final String expandedInsertSQL) throws LockException {
SQLException lastFailure = null;
for (int i = 0; i < RETRY_COUNT; i++) {
try {
lockViaInsert(conn, lockName, expandedSQL);
return;
} catch (SQLException e) {
lastFailure = e;
if ((i + 1) == RETRY_COUNT) {
getLog().debug("Lock '{}' was not obtained by: {}", lockName, Thread.currentThread().getName());
} else {
getLog().debug("Lock '{}' was not obtained by: {} - will try again.", lockName, Thread.currentThread().getName());
}
try {
Thread.sleep(1000L);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
throw new LockException("Failure obtaining db row lock: " + lastFailure.getMessage(), lastFailure);
}
private void lockViaInsert(Connection conn, String lockName, String sql) throws SQLException {
getLog().debug("Inserting new lock row for lock: '" + lockName + "' being obtained by thread: " + Thread.currentThread().getName());
PreparedStatement ps = conn.prepareStatement(sql);
try {
ps.setString(1, lockName);
ps.setLong(2, System.nanoTime());
if(ps.executeUpdate() == 0) {
throw new SQLException(Util.rtp(
"No row exists, and one could not be inserted in table " + TABLE_PREFIX_SUBST + TABLE_LOCKS +
" for lock named: " + lockName, getTablePrefix(), getSchedulerNameLiteral()));
}
} finally {
ps.close();
}
}
}
Мой ожидаемый результат - запуск 500 простых заданий каждые 5 секунд.Он должен быть разделен на несколько служб (рабочих экземпляров), но теперь я могу запустить только несколько заданий.Спасибо за любые предложения.