Spring LockRegistryLeaderInitiator делает чрезмерные вызовы в некоторых реализациях реестра блокировки - PullRequest
0 голосов
/ 05 декабря 2018

В настоящее время я работаю с LockRegistryLeaderInitiator:

org.springframework.integration.support.leader.LockRegistryLeaderInitiator

и JdbcLockRegistry:

org.springframework.integration.jdbc.lock.JdbcLockRegistry

, и я вижупроблема, когда узлы, не являющиеся лидерами, делают вызовы базы данных каждые 100 мс.

Я думаю, что могу видеть, что происходит.Инициатор лидера входит в тесную петлю, когда блокировка не удерживается:

while (isRunning()) {
    ...
    // We always try to acquire the lock, in case it expired
    boolean acquired = this.lock.tryLock(LockRegistryLeaderInitiator.this.heartBeatMillis,
            TimeUnit.MILLISECONDS);
    if (!this.locked) {
        if (acquired) {
            // Success: we are now leader
            this.locked = true;
            handleGranted();
        }
        else if (isPublishFailedEvents()) {
            publishFailedToAcquire();
        }
    }
    ...
}

Время ожидания вызова tryLock(...) контролирует скорость, с которой этот код повторяется, блокируясь на период одного такта, еслиблокировка не может быть получена.

Проблема возникает в том, как tryLock записан в некоторых реализациях LockRegistry.Возьмите JdbcLockRegistry, например:

while (true) {
    try {
        while (!(acquired = doLock()) && System.currentTimeMillis() < expire) { //NOSONAR
            Thread.sleep(100); //NOSONAR
        }
        ...
    }
    ...
}

Метод tryLock будет вращаться, многократно отправляя запросы к БД каждые 100 мс, пока не истечет время ожидания.Поэтому, хотя инициатор блокировки не удерживает блокировку, он будет повторять вызовы каждые 100 мс до бесконечности.

Мне удалось решить эту проблему с помощью следующего изменения метода LockRegistryLeaderInitiator call():

while (isRunning()) {
    try {
        ...
        //We always try to acquire the lock, in case it expired
        boolean acquired = this.lock.tryLock(); // # Make a single attempt to acquire the lock
        if (!this.locked) {
            if (acquired) {
                // Success: we are now leader
                this.locked = true;
                handleGranted();
            } else if (isRunning()) {
                // Wait before trying again.
                Thread.sleep(LockRegistryLeaderInitiator.this.heartBeatMillis); // # Make the heartbeat an explicit thread sleep.
            }
        }
        ...
    }
    ...
}

Это поведение по своему замыслу или ошибка?

Редактировать: LockRegistryLeaderInitiator имеет два свойства конфигурации для управления реакцией выборов:

/**
 * Time in milliseconds to wait in between attempts to re-acquire the lock, once it is
 * held. The heartbeat time has to be less than the remote lock expiry period, if
 * there is one, otherwise other nodes can steal the lock while we are sleeping here.
 * If the remote lock does not expire, or if you know it interrupts the current thread
 * when it expires or is broken, then you can extend the heartbeat to Long.MAX_VALUE.
 */
private long heartBeatMillis = DEFAULT_HEART_BEAT_TIME;

/**
 * Time in milliseconds to wait in between attempts to acquire the lock, if it is not
 * held. The longer this is, the longer the system can be leaderless, if the leader
 * dies. If a leader dies without releasing its lock, the system might still have to
 * wait for the old lock to expire, but after that it should not have to wait longer
 * than the busy wait time to get a new leader. If the remote lock does not expire, or
 * if you know it interrupts the current thread when it expires or is broken, then you
 * can reduce the busy wait to zero.
 */
private long busyWaitMillis = DEFAULT_BUSY_WAIT_TIME;

... и этоПохоже, что busyWaitMillis должен быть задействован, когда блокировка не удерживается и не может быть получена, но в данном случае она не используется.

1 Ответ

0 голосов
/ 05 декабря 2018

Я вижу, что есть аргумент для его настройки;но это компромисс между отзывчивостью и активностью БД.Если задержка слишком велика, вы можете никогда не получить блокировку.

Лично я не являюсь поклонником этой реализации, особенно с JDBC.

Не стесняйтесь открывать JIRAПроблема «Улучшение» для настройки режима сна.

Вклад приветствуется.

...