分布式锁-redission锁重试和WatchDog机制

一、前言:为什么你的分布式锁"有时失效"?

你是否遇到过这些问题:

  • 业务执行了 40 秒,但锁 30 秒就没了,导致超卖?
  • 多个服务同时抢锁,有的直接失败,没有重试?
  • 明明加了锁,却出现并发修改?

根本原因,很可能在于你没用好 Redisson 的两大核心机制

🔹 锁重试(Lock Retry) ------ 智能等待,避免立即失败

🔹 WatchDog(看门狗) ------ 自动续期,防止业务超时丢锁

本文将带你彻底掌握这两大机制的工作原理、使用方式与避坑指南


二、机制一:锁重试(Lock Retry)------ 智能等待,不轻易放弃

场景问题:

当多个线程/服务同时请求同一把锁时,未获得锁的一方该如何处理

  • 直接报错? → 用户体验差
  • 无限等待? → 线程阻塞,资源耗尽

Redisson 的解决方案:

提供 带超时的 tryLock() ,支持最大等待时间 + 持有时间

API 示例:
java 复制代码
RLock lock = redisson.getLock("inventory:lock");

// 最多等待 3 秒获取锁,获得后最多持有 10 秒
boolean isLocked = lock.tryLock(3, 10, TimeUnit.SECONDS);

if (isLocked) {
    try {
        // 扣减库存等业务逻辑
        deductStock();
    } finally {
        lock.unlock();
    }
} else {
    throw new BusinessException("系统繁忙,请稍后再试");
}

🔍 底层原理:

  1. 客户端尝试加锁(执行 Lua 脚本)
  2. 若失败,订阅 Redis 的解锁频道(Pub/Sub)
  3. 启动定时任务,每隔 1/3 持有时间(如 10s/3 ≈ 3.3s)重试
  4. 一旦持有者释放锁,会发布消息,唤醒所有等待者竞争

✅ 优势:避免轮询浪费 CPU,实现高效等待


三、机制二:WatchDog(看门狗)------ 自动续期,永不丢锁

经典问题重现:

java 复制代码
lock.lock(); // 默认 TTL = 30 秒
Thread.sleep(40_000); // 业务耗时 40 秒
// 此时锁已过期!其他线程可进入 → 并发安全破坏!

WatchDog 如何解决?

只要你不 unlock,锁就永远不会过期!

工作流程:
  1. 调用无参 lock() 时,不设置 TTL
  2. 同时启动后台线程(WatchDog)
  3. 每隔 10 秒internalLockLeaseTime / 3 = 30000 / 3)检查:
    • 如果当前线程仍持有该锁 → 执行 PEXPIRE myLock 30000
  4. 调用 unlock() 后,取消 WatchDog 定时任务

📊 时间线示例:

复制代码
t=0s   → 加锁,启动 WatchDog
t=10s  → WatchDog 续期(TTL 重置为 30s)
t=20s  → 再次续期
t=25s  → unlock() 被调用
t=25s+ → WatchDog 停止,锁被删除

💡 关键点 :WatchDog 只在 无参 lock() 时启用!

若使用 lock(10, SECONDS)不会启动 WatchDog,10 秒后强制过期!


四、源码级解析:WatchDog 如何实现?

核心类:org.redisson.RedissonLock

1. 加锁时注册续期任务:
java 复制代码
void scheduleExpirationRenewal(...) {
    // 将锁信息存入本地 Map
    ExpirationEntry entry = new ExpirationEntry();
    expirationRenewalMap.put(lockName, entry);
    
    // 启动定时任务
    Timeout task = commandExecutor.getConnectionManager().newTimeout(
        timeout -> {
            // 发送 PEXPIRE 命令续期
            renewExpirationAsync(threadId);
            // 递归调度下一次
            scheduleExpirationRenewal(...);
        },
        internalLockLeaseTime / 3, // 默认 10 秒
        TimeUnit.MILLISECONDS
    );
    entry.addTimeout(task);
}
2. 解锁时取消任务:
java 复制代码
void cancelExpirationRenewal(...) {
    ExpirationEntry entry = expirationRenewalMap.remove(lockName);
    if (entry != null) {
        for (Timeout timeout : entry.getTimeouts()) {
            timeout.cancel(); // 取消所有定时任务
        }
    }
}

设计精妙:通过本地 Map + Netty Timeout 实现高效管理


五、锁重试 + WatchDog 联合使用示例

java 复制代码
public void seckill(Long productId, Long userId) {
    RLock lock = redisson.getLock("seckill:product:" + productId);
    
    try {
        // 最多等待 2 秒抢锁,抢到后由 WatchDog 自动续期
        if (lock.tryLock(2, TimeUnit.SECONDS)) {
            // 业务可能耗时较长(如调用风控、支付)
            doSeckillBusiness(productId, userId);
        } else {
            log.warn("用户 {} 抢购商品 {} 失败:锁等待超时", userId, productId);
            throw new BusinessException("活动太火爆,请稍后再试");
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new RuntimeException(e);
    } finally {
        if (lock.isHeldByCurrentThread()) {
            lock.unlock(); // 安全解锁
        }
    }
}

最佳实践

  • 抢锁阶段 :用 tryLock(waitTime) 避免无限阻塞
  • 持有阶段:依赖 WatchDog 自动续期,无需担心业务超时

六、常见误区与避坑指南

❌ 误区 1:认为 lock(30, SECONDS) 会自动续期

真相只有无参 lock() 才启动 WatchDog
lock(30, SECONDS) 表示"最多持有 30 秒",到期强制释放。

❌ 误区 2:在异步线程中 unlock()

java 复制代码
lock.lock();
CompletableFuture.runAsync(() -> {
    lock.unlock(); // ❌ threadId 不匹配,无法解锁!
});

正解 :解锁必须在加锁的同一线程中进行

❌ 误区 3:忘记判断是否持有锁就 unlock()

风险 :可能抛出异常或误删他人锁
建议 :使用 lock.isHeldByCurrentThread() 判断


七、性能与可靠性对比

方案 是否支持重试 是否自动续期 适用场景
手写 Redis SET NX 简单低并发
Redisson lock() ✅(阻塞) 通用高可靠
Redisson tryLock(w, h) ✅(超时) ✅(仅无参 holdTime) 用户交互型业务

📌 推荐

  • 后台任务 → 用 lock()
  • Web 请求 → 用 tryLock(waitTime, leaseTime)

八、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
kobe_t5 小时前
分布式定时任务系列14:XXL-job的注册模型
分布式
Knight_AL5 小时前
线程池满了怎么办?用 RabbitMQ 做任务补偿不丢失
分布式·rabbitmq·ruby
難釋懷7 小时前
分布式锁-redission锁的MutiLock原理
分布式
小北方城市网8 小时前
RabbitMQ 生产级实战:可靠性投递、高并发优化与问题排查
开发语言·分布式·python·缓存·性能优化·rabbitmq·ruby
乾元8 小时前
拒绝服务的进化:AI 调度下的分布式协同攻击策略
人工智能·分布式
听麟9 小时前
HarmonyOS 6.0+ PC端多设备文件拖拽协同开发实战:手眼同行增强与分布式软总线深度应用
分布式·华为·harmonyos
前端世界10 小时前
鸿蒙分布式网络性能优化实战:从通信建连到多设备协同
网络·分布式·harmonyos
雪碧聊技术11 小时前
什么是Zookeeper?
分布式·zookeeper
李白你好11 小时前
基于腾讯云函数 (SCF) 的分布式 IP 代理池.
分布式·tcp/ip·腾讯云