Redisson分布式锁的看门狗机制探究

24 年 11 月 28 日 星期四
746 字
4 分钟

以下是优化后的文章格式,主要是改善了排版、标题层级和代码块的清晰度,方便阅读:

问题背景

在一个使用Spring AOP实现防重复提交功能的项目中,我们发现了一个有趣的现象:通过 @KaiNoRepeatSubmit 注解设置的锁过期时间(10秒)并没有生效,而是始终保持30秒才过期。这引发了我们对Redisson分布式锁实现机制的深入探究。

问题分析过程

1. 初始实现

最初的实现使用了Spring AOP的环绕通知和后置通知:

java
@Around(value = "noRepeatSubmitPoint(kaiNoRepeatSubmit)")
public Object judgeRepeatSubmit(ProceedingJoinPoint joinPoint, KaiNoRepeatSubmit kaiNoRepeatSubmit) throws Throwable {
    String key = getRequestKey(joinPoint, kaiNoRepeatSubmit);
    long seconds = kaiNoRepeatSubmit.seconds(); // 设置为10秒
    if (!kaiRedissonLockComponent.getLock(key, seconds, TimeUnit.SECONDS)) {
        return new DWServiceResult(false, "重复请求");
    }
    return joinPoint.proceed();
}

@After(value = "noRepeatSubmitPoint(kaiNoRepeatSubmit)")
public void afterMethod(JoinPoint joinPoint, KaiNoRepeatSubmit kaiNoRepeatSubmit) {
    kaiRedissonLockComponent.removeLock(getRequestKey(joinPoint, kaiNoRepeatSubmit));
}

2. 问题发现

通过日志观察,我们发现:

  • 锁的获取是成功的
  • 业务方法执行完成后锁被释放
  • 但锁的实际过期时间仍然是30秒
  • 这与我们设置的10秒明显不符

3. 深入分析

进一步研究发现这与Redisson的看门狗(WatchDog)机制有关:

Redisson默认配置

  • 看门狗超时时间为30秒
  • 会在锁的过期时间剩余1/3时自动续期
  • 续期时会将过期时间重置为30秒

实际执行流程

  • 时间点1: 00:00:00 - 在 @Around 中设置10秒锁
    • Redisson同时启动看门狗线程
  • 时间点2: 00:00:01 - 业务方法执行完成
    • @After 执行,调用 removeLock
  • 时间点3: 00:00:01 - 看门狗线程仍在运行
    • 锁的过期时间被重置为30秒

解决方案

1. 配置修改

在Redisson配置中禁用看门狗机制:

java
@Bean
public RedissonClient redissonClient() {
    Config config = new Config();
    // ... 其他配置 ...
    config.setLockWatchdogTimeout(0L); // 禁用看门狗
    return Redisson.create(config);
}

2. 锁实现优化

修改锁的获取方式,避免看门狗干扰:

java
public boolean getLock(String lockName, long expireTime, TimeUnit timeUnit) {
    try {
        RLock lock = redissonClient.getLock(lockName + LOCK_FLAG);
        return lock.tryLock(0, expireTime, timeUnit);
    } catch (Exception e) {
        LOGGER.warn("获取锁失败", e);
        return false;
    }
}

3. 移除手动释放

删除 @After 注解方法,让锁自然过期:

java
@Around(value = "noRepeatSubmitPoint(kaiNoRepeatSubmit)")
public Object judgeRepeatSubmit(ProceedingJoinPoint joinPoint, KaiNoRepeatSubmit kaiNoRepeatSubmit) throws Throwable {
    String key = getRequestKey(joinPoint, kaiNoRepeatSubmit);
    if (!kaiRedissonLockComponent.getLock(key, kaiNoRepeatSubmit.seconds(), TimeUnit.SECONDS)) {
        return new DWServiceResult(false, "重复请求");
    }
    return joinPoint.proceed();
}

经验总结

  1. Redisson的看门狗机制是一把双刃剑
  • 优点: 防止分布式锁因节点宕机而无法释放
  • 缺点: 可能干扰预期的锁行为
  1. 正确使用分布式锁需要
  • 理解底层实现机制
  • 根据业务需求选择合适的配置
  • 避免过度设计
  1. 实践建议
  • 明确锁的使用场景
  • 选择合适的过期策略
  • 做好监控和日志记录

参考资料


这个优化版更注重清晰的结构、代码的突出显示以及段落的分隔,以提升文章的可读性和逻辑性。

文章标题:Redisson分布式锁的看门狗机制探究

文章作者:Jinx

文章链接:https://blog.mytest.cc/posts/redisson-distributed-lock-watchdog[复制]

最后修改时间:


商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接,您可以自由地在任何媒体以任何形式复制和分发作品,也可以修改和创作,但是分发衍生作品时必须采用相同的许可协议。
本文采用CC BY-NC-SA 4.0进行许可。