【深度复盘】Redis 分布式锁:从 SETNX 到 Redisson 看门狗的架构权衡

【深度复盘】Redis 分布式锁:从 SETNX 到 Redisson 看门狗的架构权衡

标签: Redis 分布式锁 Redisson 并发编程 架构设计
复盘时间: 2026-01-25

一、 为什么需要分布式锁?(演进之路)

在单机多线程环境下,我们使用 synchronizedReentrantLock;但在微服务/集群环境下,本地锁无法锁住其他 JVM 进程,因此需要引入第三方组件(Redis/Zookeeper)来实现全局锁。

1. 原始阶段:SETNX

  • 命令: SETNX lock:key value (Set if Not Exists)
  • 致命缺陷: 如果机器宕机或程序崩溃,锁未释放(死锁)。
  • 补丁: 引入过期时间(TTL)。

2. 进阶阶段:原子性与误删

  • 原子性问题: SETNXEXPIRE 是两步操作,非原子。
    • 解决: 使用 Redis 2.6+ 复合命令:SET key value EX 10 NX
  • 误删问题: 线程 A 卡顿,锁过期自动释放;线程 B 上锁;线程 A 醒来执行 DEL,把线程 B 的锁删了。
    • 解决: UUID + Lua 脚本
    • Value 存入唯一 ID(如 UUID),删除前判断 if (get(key) == uuid) { del(key) },必须通过 Lua 保证判断和删除的原子性。

3. 终极阶段:续期问题

  • 痛点: 业务没跑完,锁过期了怎么办?
  • 解决: 引入 守护线程(Daemon Thread) 自动续期。这就是 Redisson 的核心价值。

二、 Redisson 核心机制深度解析

1. 看门狗 (WatchDog) 机制

  • 触发条件: 加锁时不指定 LeaseTime(租约时间)。
  • 原理:
    • 默认租约时间 (lockWatchdogTimeout) 为 30秒
    • Redisson 启动一个后台线程,每隔 10秒 (1/3 租约时间) 检查一次,如果主线程还持有锁,就重置过期时间为 30秒。
  • 停止条件: 显式解锁 (unlock) 或 客户端宕机(看门狗线程随之死亡,30秒后锁自动过期)。

2. 架构哲学:Safety vs Liveness(面试杀手锏)

问题: 如果业务代码死循环,看门狗一直续期导致锁无法释放(死锁),是不是不如"固定过期时间"好?

架构决策:

  • 场景 A:固定过期时间(无看门狗)
    • 业务死循环 -> 锁过期释放 -> 其他线程进入 -> 并发修改同一数据。
    • 后果: 脏写 (Dirty Write) 。数据被污染,账平不上了。(Safety 丢失)
  • 场景 B:看门狗自动续期
    • 业务死循环 -> 锁一直存在 -> 其他线程拿不到锁(阻塞)。
    • 后果: 服务停摆 (Deadlock) 。业务卡住,但数据是安全的。(Liveness 丢失)

结论: 对于金融/交易等核心业务,数据一致性(Safety)高于可用性(Liveness) 。宁可人工介入重启服务解决死锁,也不能容忍数据被脏写。因此,看门狗机制是核心业务的"保护神"

3. 锁等待机制:Pub/Sub vs 自旋

  • SETNX: 失败返回 0,客户端通常需要 while(true) 自旋重试,消耗 CPU。
  • Redisson: 利用 Redis 的 Pub/Sub(发布订阅)
    • 获取锁失败时,订阅锁的释放频道,然后挂起当前线程(Semaphore)。
    • 收到释放消息后,唤醒线程再次尝试。
    • 优势: 无效等待时不耗 CPU,性能更优。

三、 Redisson API 实战指南

在代码中,根据业务场景选择不同的锁策略:

1. 死磕模式(核心业务)

适用于必须执行且不能并发的任务(如每日跑批、资金结算)。

java 复制代码
RLock lock = redisson.getLock("myLock");
lock.lock(); // 激活看门狗,默认30s,自动续期
try {
    // 业务逻辑(哪怕跑1小时也不怕)
} finally {
    lock.unlock();
}

2. 优雅等待模式(高并发 Web 业务)

适用于大多数互联网请求,防止请求堆积。

java 复制代码
// 尝试等待10秒,拿到锁后,锁在30秒后强制过期(无看门狗!)
// 参数:waitTime, leaseTime, unit
boolean res = lock.tryLock(10, 30, TimeUnit.SECONDS); 
if (res) {
   try {
     // 业务处理
   } finally {
     lock.unlock();
   }
} else {
   throw new RuntimeException("系统繁忙,请稍后再试"); // 快速失败
}

注意: 一旦指定了 leaseTime(第二个参数),看门狗机制失效

3. 快速失败模式(防抖/非核心)

适用于防止用户重复点击。

java 复制代码
if (lock.tryLock()) { // 不等待,拿不到立刻返回 false
    try { ... } finally { lock.unlock(); }
} else {
    return;
}

四、 总结(记忆钩子)

  1. 原子性: 加锁用 SET ... NX EX,解锁用 Lua 脚本。
  2. 误删: Value 必须存 UUID 做身份验证。
  3. 看门狗: 解决"业务没跑完锁过期"的问题。不传 leaseTime 时触发。
  4. 取舍: 核心业务选看门狗(保数据),高并发业务选固定过期时间(保服务)。
相关推荐
虹科网络安全3 小时前
艾体宝产品|深度解读 Redis 8.4 新增功能:原子化 Slot 迁移(上)
数据库·redis·bootstrap
AI自动化工坊3 小时前
Late框架技术深度解析:5GB VRAM实现10倍AI编码效率的工程架构
人工智能·5g·架构·ai编程·late
空中海3 小时前
第六篇:架构篇 — 微服务、部署、高并发与专家级能力
微服务·云原生·架构
Wave8454 小时前
基于 STM32 + ESP8266 + W25Q64 的双核 OTA 底层架构总结
stm32·嵌入式硬件·架构
苍煜4 小时前
分布式事务生产实战选型对比
分布式
yongyoudayee5 小时前
CRM架构演进:从记录系统到执行引擎的技术解析
架构
源码宝5 小时前
基于 SpringBoot + Vue 的医院随访系统:技术架构与功能实现
java·vue.js·spring boot·架构·源码·随访系统·随访管理
有马贵将6 小时前
【5】微前端知识点总结
前端·架构
虹科网络安全6 小时前
艾体宝新闻|Redis 月度更新速览:2026 年 3 月
数据库·redis·缓存
ting94520006 小时前
深入解析 Social Fetch 机制:原理、架构、应用场景、实战落地与性能优化全攻略
人工智能·性能优化·架构