Redis 分布式锁与 Redisson:从抢券超卖讲到 WatchDog、可重入和 RedLock

分布式锁最适合用真实业务来理解。抢券场景:多个用户同时抢优惠券,系统要保证库存不能被扣成负数。

如果代码部署在单机上,synchronized 可能够用;但服务一旦集群部署到多个 Tomcat 实例,本地锁就只能锁住当前 JVM,挡不住其他节点上的线程。

这就是 Redis 分布式锁的使用场景:集群环境下,让多个服务实例争抢同一把锁。

一、为什么抢券会超卖?

普通抢券逻辑大概是:

java 复制代码
Integer num = redisTemplate.opsForValue().get("num");
if (num == null || num <= 0) {
    throw new RuntimeException("优惠券已抢完");
}
num = num - 1;
redisTemplate.opsForValue().set("num", num);

两个线程可能同时读到库存 1,然后都判断库存充足,最终都扣减成功。
Redis 库存 线程2 线程1 Redis 库存 线程2 线程1 查询库存 = 1 查询库存 = 1 扣减为 0 扣减为 0

问题不在 Redis,而在"查询库存"和"扣减库存"不是一个不可被打断的整体。

二、SETNX 实现分布式锁

Redis 实现分布式锁主要依赖 SETNX,也就是 SET if Not eXists:key 不存在时才能设置成功。

现在更推荐用一条 SET 命令同时完成加锁和设置过期时间:

text 复制代码
SET lock:coupon threadId NX EX 10

含义是:只有 lock:coupon 不存在时才设置成功,并且 10 秒后自动过期。
成功
失败
尝试获取锁
SET NX EX 是否成功
执行业务
释放锁
等待或重试

释放锁时也要小心,必须确认这把锁是自己的,再删除。否则线程 A 的锁过期后,线程 B 获取了新锁,线程 A 再执行删除就可能误删线程 B 的锁。

所以释放锁通常要用 Lua 脚本保证"判断锁标识 + 删除锁"是原子操作。

三、Redisson 做了哪些封装?

Redisson 是 Redis 分布式锁的成熟封装。课件里提到几个重点:

  1. 底层基于 SETNX 和 Lua 脚本保证原子性。
  2. 使用 WatchDog 给锁自动续期。
  3. 使用 Hash 结构记录线程标识和重入次数,实现可重入。
  4. 支持锁重试等待。

四、WatchDog:锁怎么自动续期?

如果业务执行时间超过锁过期时间,锁提前释放,就会有并发问题。Redisson 的 WatchDog 会在持有锁的线程还没执行完时自动续期。
Redis WatchDog 业务线程 Redis WatchDog 业务线程 加锁成功 定期检查锁仍被当前线程持有 续期锁过期时间 业务完成后释放锁

默认情况下,WatchDog 会周期性续期,避免业务还没执行完锁就过期。

五、可重入锁:为什么用 Hash?

可重入指的是同一个线程已经拿到锁后,可以再次获取同一把锁。

Redisson 会用 Hash 结构记录线程 id 和重入次数:

text 复制代码
heimalock
  thread-1 -> 2

同一个线程再次加锁时,重入次数加 1;释放锁时,重入次数减 1;只有减到 0 才真正删除锁。
线程第一次加锁
重入次数 = 1
线程再次加锁
重入次数 = 2
释放一次,重入次数 = 1
再次释放,删除锁

六、主从一致性和 RedLock

Redis 主从架构下,分布式锁还有一个风险:线程在 Master 上加锁成功,但锁还没同步到 Slave,Master 就宕机了。Slave 被提升为新 Master 后,其他线程可能又获取到同一把锁。

RedLock 的思路是:不要只在一个 Redis 实例上加锁,而是在多个独立 Redis 节点上加锁,只要超过 n / 2 + 1 个节点成功,就认为加锁成功。

但课件也提醒:RedLock 性能较差,不是默认推荐方案。如果业务真的要求极强一致,建议考虑 ZooKeeper 这类更适合强一致锁的方案。

七、面试回答模板

可以这样答:

我们项目里在抢券、幂等性或集群定时任务场景用过分布式锁。Redis 分布式锁底层主要依赖 SET NX EX 加锁,并用 Lua 脚本保证释放锁时判断和删除的原子性。实际项目里一般使用 Redisson,它封装了 WatchDog 自动续期、可重入锁、锁重试等能力。Redisson 的可重入基于 Hash 结构记录线程标识和重入次数。至于主从一致性问题,RedLock 可以缓解但性能较差,如果业务必须强一致,应该考虑 ZooKeeper。

相关推荐
ai_coder_ai19 小时前
分布式缓存架构设计与实践
分布式·缓存
凡尘——雨落凡尘19 小时前
PHP 线上十大隐形故障复盘:90% 的网站卡顿、502、雪崩,都是这些细节导致的
redis·nginx·php·session
纯真时光19 小时前
微服务分布式事务 -- XA,AT,TCC模式
分布式·微服务
一水21 小时前
Redis实战:一个AI工作流系统里的五个应用场景,从传参到限流的完整链路
数据库·redis·wpf
笨蛋不要掉眼泪1 天前
RabbitMQ消息队列:业务幂等性
分布式·rabbitmq·java-rabbitmq
鹿角片ljp1 天前
Redis 深度复习:从入门到面试通关
数据库·redis·面试
Volunteer Technology1 天前
Kafka的消费全流程
分布式·kafka·linq
网教盟人才服务平台1 天前
Redis Key集中过期引发的流量雪崩实战解析
数据库·redis·缓存
openYuanrong分布式计算引擎1 天前
openYuanrong 打造 Agent 时代的企业级分布式底座
人工智能·分布式·ai·serverless
Jul1en_1 天前
【Java 脚手架】封装通用工具类-1
java·spring boot·分布式·spring·spring cloud