Redisson-lock看门狗原理

本文详细解析了Redisson分布式锁的tryLockInnerAsync和renewExpirationAsync方法,介绍了如何通过设置超时时间和看门狗机制实现自动续期,以及lock.lock()函数的解锁策略。重点讨论了锁的默认30秒过期时间和10秒自动解锁策略。

Redisson-lock看门狗原理

8. 分布式锁和同步器 · redisson/redisson Wiki · GitHub

默认-1

image-20220831162445593

传入自己的时间(此处为10) 不会执行看门狗,不等于-1,如果是默认的话,等于-1

image-20220831162321988

进入tryLockInnerAsync,发现直接执行脚本

<T> RFuture<T> tryLockInnerAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
    return this.evalWriteAsync(this.getRawName(), LongCodec.INSTANCE, command, "if (redis.call('exists', KEYS[1]) == 0) then redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; return redis.call('pttl', KEYS[1]);", Collections.singletonList(this.getRawName()), new Object[]{unit.toMillis(leaseTime), this.getLockName(threadId)});
}

image-20220831163354777


image-20220831164632188

protected RFuture<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));
}

  1. 锁的自动续期,如果业务超长,运行时间自动给锁续上新的30秒。不用担心业务时间长。
  2. 加锁的任务只要运行完成,就不会给当前锁续期,即使不手动删锁。锁默认30秒后删除

lock.lock(10, TimeUnit.SECONDS);

  • 10秒钟自动解锁,自动解锁时间一定要大于业务时间

问题:lock.lock();在锁时间到了以后,不会自续期

  • 1、如果我们传递了锁的超时时间,就发送给redis脚本,进行占锁,默认超时时间就是我们设置的时间

  • 2、如果我们未指定锁的超时时间,就使用 30*1000 (LockWatchdogTimeout看门狗的默认时间);
    只要占锁成功,leaseTime=-1就会启动一个定时任务

    • [重新给锁设置过期时间,新的过期时间就是看门狗的默认时间30s],每隔10s都会自动续期30s
      internalLockLeaseTime(看门狗时间)/3,10s
@ResponseBody
@GetMapping("/hello")
public String hello(){
    //1、获取一把锁,只要锁的名字一样,就是同一把锁
    RLock lock = redissonClient.getLock("myLock");
    //2、加锁
    lock.lock();//阻塞式等待,没拿到锁,一直等待。默认加锁30秒
    
    //最佳实战
    //       lock.lock(10, TimeUnit.SECONDS);//10秒钟自动解锁,自动解锁时间一定要大于业务时间
    // 省掉了整个续期操作。手动解锁
    try {
        System.out.println("加锁成功,执行业务"+Thread.currentThread().getId());
        Thread.sleep(30000);
    } catch (InterruptedException e) {

    } finally {
        //3、解锁,假设解锁代码没有运行,redisson会不会出现死锁
        System.out.println("释放锁"+Thread.currentThread().getId());
        lock.unlock();
    }
    return "hello";
}

image-20220831165516475

### Redisson 分布式锁中超时看门狗的实现原理 在分布式环境中,为了防止死锁并确保资源能够及时释放,通常会对锁设置一个超时时间。然而,在实际应用中,可能会遇到业务逻辑处理时间超过预期的情况。为此,Redisson引入了看门狗(watchdog)机制来解决这一问题。 当客户端成功获取到锁之后,Redisson内部会启动一个定时器任务,该任务负责定期检查当前持有的锁是否已经接近过期[^2]。具体而言: - **默认配置**:每次获得锁时,Redisson会给这个锁设定一个初始的有效期限,默认情况下为30秒。 - **续期操作**:一旦持有锁的时间超过了总有效期的一半以上(例如15秒),看门狗就会触发一次续期请求,将锁的有效期再延长至完整的30秒。这样的过程会持续进行,只要锁还没有被显式地解锁或因其他原因失效。 - **间隔策略**:按照预设算法计算下次续期的最佳时机,通常是每经过大约三分之一的有效期间隔就尝试更新一次锁的有效期。比如,假设有效时间为30秒,则每隔约10秒钟左右就会有一次续期动作[^3]。 这种设计可以有效地避免因为网络延迟或其他不可预见的因素而导致提前失去锁控制权的风险,同时也保障了即使是在极端条件下也能安全可靠地管理共享资源访问权限。 此外,值得注意的是,只有当线程确实处于活动状态并且继续占用着对应的锁实例时,才会执行上述提到的自动延展流程;反之,如果线程正常结束或者异常终止,则不再会有任何关于此特定锁的操作发生[^4]。 ```java // Java代码示例展示如何使用RedissonClient创建RLock对象,并通过tryLock方法指定等待时间和租约时间 import org.redisson.api.RLock; import java.util.concurrent.TimeUnit; public class DistributedLockExample { private final RedissonClient redissonClient; // 假定已初始化 public void acquireDistributedLock() throws InterruptedException { RLock lock = redissonClient.getLock("myLock"); boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS); // 尝试加锁,最多等待10秒,锁定后保持30秒 if (isLocked) { try { // 执行临界区内的业务逻辑... } finally { lock.unlock(); // 确保最终总是能释放锁 } } } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值