Redis分布式锁核心风险是锁过期而业务未完成,导致并发冲突;需基于压测数据设初始TTL并加20%~50%缓冲,启用带身份校验的自动续期(如Redisson的Watchdog),解锁必须用Lua脚本比对token。

加锁成功但业务执行超时,是 Redis 分布式锁最典型的风险场景:锁过期了,任务还在跑,另一个客户端趁机拿到锁,两个线程同时操作临界资源,数据就乱了。核心不是“能不能加锁”,而是“锁能不能活到任务结束”。解决的关键在于让锁的生命周期与业务实际执行时间对齐,而不是靠拍脑袋设一个固定值。
合理设置初始 TTL 并预留缓冲
不能完全不设过期时间,否则节点宕机就会死锁。但也不能随便写个 5 秒或 30 秒。要基于真实压测数据估算业务最大耗时,再加 20%~50% 缓冲。比如订单支付核验平均耗时 800ms,P99 是 1.6s,那初始 TTL 至少设为 2500ms。这个值不是一成不变的,上线后应结合监控(如慢调用告警、锁释放日志)持续优化。
启用自动续期(Watchdog)机制
这是应对长尾延迟最有效的手段。原理很简单:加锁成功后,启动一个后台守护线程(或协程),周期性检查当前锁是否仍由本客户端持有,若是,则重置 TTL。例如每 10 秒检查一次,将锁有效期刷新为原始 TTL(如 30 秒)。注意两点:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 续期前必须校验锁 value 是否等于本客户端的唯一标识(如 UUID),防止给别人的锁续命
- 续期操作本身要用原子方式,推荐用 Lua 脚本实现:先 GET 再 EXPIRE,避免竞态
解锁必须绑定身份校验
即使有续期,也不能放松解锁环节。不能直接 DEL key,而要确保只有加锁者才能删锁。标准做法是:
- 加锁时,value 写入客户端唯一 token(如 client-uuid-abc123)
- 解锁时,用 Lua 脚本比对 key 对应的 value 是否匹配,匹配才执行 del
- 脚本示例:
if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end
优先使用成熟封装,别手撸基础逻辑
Redisson 就是为此类问题而生的。它默认开启 Watchdog(默认锁有效期 30 秒,每 10 秒续一次),value 自动带 UUID,解锁自动走 Lua 校验,还支持可重入、等待队列、失败回调等。一行 lock.lock() 就规避了 90% 的坑。自己实现容易遗漏时钟漂移、网络分区、续期失败降级等边界情况,除非有强定制需求,否则不建议从零造轮子。

















