Redisson的WatchDog机制是Redisson提供的监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。当一个拿到锁的线程一直没有完成逻辑,那么看门狗会帮助线程不断的延长锁超时时间,锁不会因为超时而被释放。默认情况下,看门狗的续期时间是30s,也可以通过修改Config.lockWatchdogTimeout来另行指定。
关于为什么不直接设置永久有效
直接设置永久有效的话,客户端崩溃后锁得不到释放,从而产生死锁,而看门狗机制则不会。
如果持有锁的客户端因为任何原因(比如崩溃或网络中断)无法继续工作,WatchDog将不再续期,这样锁将在其剩余的有效期内自然过期,从而释放出来供其他等待的客户端获取。这种方式提高了系统的鲁棒性和资源利用率,避免了死锁问题。
相关源码
//watchDog启动
private void renewExpiration() {
ExpirationEntry ee = EXPIRATION_RENEWAL_MAP.get(getEntryName());
if (ee == null) {
return;
}
Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.get(getEntryName());
if (ent == null) {
return;
}
RFuture<Boolean> future = renewExpirationAsync("EXPIRE", ent.getLockName(), internalLockLeaseTime);
future.onComplete((res, e) -> {
if (e != null) {
log.error("Can't update lock " + getEntryName() + " expiration", e);
return;
}
if (res) {
// reschedule itself
renewExpiration();
}
});
}
}, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);
ee.setTimeout(task);
}
//WatchDog的停止
private void cancelExpirationRenewal() {
ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.get(getEntryName());
if (ent == null) {
return;
}
Timeout timeout = ent.getTimeout();
if (timeout != null) {
timeout.cancel();
}
EXPIRATION_RENEWAL_MAP.remove(getEntryName());
}
//WatchDog的续期
private RFuture<Boolean> renewExpirationAsync(String command, String key, long leaseTime) {
return commandExecutor.evalWriteAsync(key, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return 1; " +
"end; " +
"return 0;",
Collections.<Object>singletonList(getEntryName()),
leaseTime, getLockName());
}