资深面试官:你们项目中的分布式锁是怎么实现的?
老任:基于redis的set命令,该命令有nx和ex选项。
资深面试官:那如果锁到期了,业务还没结束,如何进行自动续期呢?
老任:这个......面试官,您上个问题是啥来着?
资深面试官:你们项目中分布式锁是怎么实现的。
老任:我们直接使用了Redisson中提供的分布式锁。
资深面试官:你给我滚!!!
Redisson的看门狗机制
使用redis分布式锁时,为了防止种种异常情况下,锁无法正常“释放”的情况,我们都会为锁设置个超时时间。
这时候,又会存在一个尴尬的情况,如果设置了超时时间,但在规定的时间内,业务逻辑还没有执行完,锁就被释放了......那么针对一些特定的业务逻辑,这可能又会引起新的问题......
所以Redisson就给我们提供了监控锁的看门狗机制,通过该机制,锁被关闭前,看门狗会不断的延长锁的超时时间。默认情况下,看门狗的锁超时时间lockWatchdogTimeout是30s,该值当然也是可以设置的。
源码伺候
现在让我们进入tryLock()方法来查看一下实现源码,在该方法中调用tryAcquire()方法。
tryAcquire()方法中调用tryAcquireAsync()方法。
tryAcquireAsync()方法中,如果leaseTime小于等于0,调用scheduleExpirationRenewal方法进行续期。
从该方法中看到,leaseTime表示锁的超时时间,如果调用tryLock方法加锁时,设置了该参数,看门狗机制不会生效。
scheduleExpirationRenewal()方法中调用了renewExpiration()方法。
renewExpiration()方法中启用了一个timeout定时器,internalLockLeaseTime的1/3时间去执行续期操作,续期的方法是renewExpirationAsync()。
renewExpirationAsync的方法内容如下,里面定义了lua脚本,如果key存在,执行pexpire命令进行续期操作。
protected CompletionStage<Boolean> renewExpirationAsync(long threadId) {
return this.evalWriteAsync(
this.getRawName(),
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.singletonList(this.getRawName()),
this.internalLockLeaseTime,
this.getLockName(threadId));
}
以上就是redis分布式锁到期后,业务还没结束时的自动续期解决方案,现在你会了吗?关注Java架构栈,干货天天都不断哦