Проблемы с производительностью в Quartz Scheduler с использованием MemSQL в качестве постоянного хранилища - PullRequest
0 голосов
/ 17 февраля 2019

У меня возникают проблемы с производительностью, когда я использую 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 секунд.Он должен быть разделен на несколько служб (рабочих экземпляров), но теперь я могу запустить только несколько заданий.Спасибо за любые предложения.

...