同一笔订单被扣了两次库存,日志里两个线程加锁时间差 12 秒,锁的 TTL 却早就查不到了。日志里能对上时间点,这种反而好排。

锁的过期时间是按最坏情况随手写的固定值,业务执行超过这个时长锁自动释放,第二个请求立刻拿到锁,互斥形同虚设,也没人看业务跑完没有。这一点先确认清楚,后面就不用反复试。

SET lock:order:8812 7f3a2c NX PX 10000
# 每 3 秒续期一次
PEXPIRE lock:order:8812 10000
# 释放前先比对 value

这次卡住的地方就在「Redis 锁续期」这一环,单独把它拎出来验证,别和其他改动混在同一次发布里。先做最小复现,能稳定跑出来的问题,排查成本会低一个数量级。

别只看报错的最后一行,往上看几行,真正的起因通常在上面。同类问题如果隔一段时间又出现,多半是某个定时任务或重启流程把改动冲掉了。

处理上按这个顺序:起一个守护线程 每过三分之一 TTL 就续一次;释放时用 lua 比对 value 再删 避免误删;确实长耗时的业务单独放宽 TTL 并加时长监控。

结果对不对很好判断,并发压同一单号跑一轮,库存只扣一次,锁释放后键已不存在。

作者 9823189