导读:很多团队用Redisson加分布式锁,图的就是它有看门狗自动续期,业务不用算过期时间。但线上还是出过"锁提前释放、两个线程并发写同一份库存"的事故。这篇把看门狗续期失效的三种真实场景、复现方式和修复点写清楚,附可运行的最小复现代码。
Redisson加锁时不指定leaseTime,默认锁30秒;后台启动一个定时任务,每10秒(过期时间的三分之一)检查一次:如果持锁线程还活着,就把锁重新续到30秒。
它的设计前提是三个:1.持锁线程还在跑、没被卡住;2.续期请求能正常打到Redis;3.锁确实还在自己手里(用唯一value判断)。下面三种失效,分别打破这三个前提中的一个。
看门狗的续期任务,是跑在Redisson自己的调度线程池里。但如果你的业务逻辑里调用了同一个Redis连接池做阻塞操作,连接池被打满,续期命令就排不进去,30秒一到锁自动释放。最小复现:
RLock lock = redissonClient.getLock("order:1001");
try {
lock.lock();
Thread.sleep(35000);
} finally {
lock.unlock();
}修复点:看门狗调度池和业务Redis调用池分开;关键长任务显式指定一个足够长的leaseTime,不要完全依赖看门狗;业务方法里不要做不可控的阻塞等待。
看门狗每10秒续一次,看着留了20秒余量。但JVM一次Full GC停顿15秒,续期任务被挂起,等GC结束锁已经过期。这时候另一个线程加锁成功,两个线程同时进入临界区。
这不是Redisson的bug,是所有"本地调度+远程过期"方案共有的脆弱点。
修复点:关键业务监控GC停顿,STW超过3秒就要告警;锁的过期时间不要用默认30秒,按业务最大执行时间设一个保守值;临界区里的操作必须是幂等的。
这是最隐蔽的一种。线程A在主节点加锁成功,看门狗还没来得及把锁同步到从节点,主节点宕机、从节点升主。新主上根本没有这把锁,线程B过来直接加锁成功。
Redisson的看门狗解决不了主从复制的异步延迟,这是Redis主从架构下分布式锁的经典问题。
修复点:对正确性要求极高的场景,用RedLock多实例加锁;或者退一步承认锁只用于减少冲突,真正的正确性由数据库唯一约束、乐观锁、幂等键来保证;主从切换期间做好故障演练。
Q:锁过期了但业务还在跑,会发生什么?
A:另一个线程能加锁成功,两个线程进入同一临界区。后果取决于业务是否幂等:幂等操作最坏重复一次,非幂等操作会把同一份数据写两遍。
Q:RedLock真的比单节点锁安全吗?
A:它降低了主从切换丢锁的概率,但引入了多时钟漂移和网络分区的复杂度。工程上更常见的做法是锁做粗粒度互斥,数据库做最终正确性。
Q:看门狗默认30秒、每10秒续期,能改吗?
A:能,在Redisson配置里改lockWatchdogTimeout。改之前先确认业务最大执行时间,把续期间隔和过期时间一起调。
分布式锁的看门狗是个工程便利,不是正确性保证。它能挡住业务比预估慢一点的常见情况,但挡不住GC停顿、连接池阻塞、主从切换。真正的正确性,永远在临界区的幂等和数据库约束里。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。