Java Spring LockRegistryLeaderInitiator在某些锁注册表实现中调用过多

Java Spring LockRegistryLeaderInitiator在某些锁注册表实现中调用过多,java,spring,spring-integration,Java,Spring,Spring Integration,我目前正在使用LockRegistryLeaderInitiator: org.springframework.integration.support.leader.LockRegistryLeaderInitiator 以及jdbclock注册表: org.springframework.integration.jdbc.lock.JdbcLockRegistry 我发现一个问题,非领导者节点每100毫秒调用一次数据库 我想我能看到发生了什么。当锁未保持时,先导启动器进入紧循环: while

我目前正在使用LockRegistryLeaderInitiator:

org.springframework.integration.support.leader.LockRegistryLeaderInitiator

以及jdbclock注册表:

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(…)
调用的超时通过阻塞一个心跳周期来控制此代码循环的速度

问题发生在某些LockRegistry实现中tryLock的编写方式上。以JdbcLockRegistry为例:

while (true) {
    try {
        while (!(acquired = doLock()) && System.currentTimeMillis() < expire) { //NOSONAR
            Thread.sleep(100); //NOSONAR
        }
        ...
    }
    ...
}
这种行为是设计的还是bug

编辑: 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,但无法获取,但在这种情况下,似乎没有使用它。

我可以看出,有一个理由支持配置它;但这是响应能力和数据库活动之间的权衡。如果延迟时间太长,您可能永远得不到锁

就个人而言,我不喜欢这种实现,尤其是JDBC

您可以随意打开一个窗口,使睡眠可配置

欢迎捐款

/**
 * 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;