<p style="text-align:center"><img src="https://platform-outputs.agnes-ai.space/images/t2i/task_oItDyjsqtI4IMZRbH62BvAYloCfqmw77/output_9a9cc4490fe3466dae3ccc91caa76962.png" alt="封面图" style="max-width:100%;height:auto" /></p>
记一次Redis分布式锁实现线上排查:Redlock算法与 Lua 脚本
昨天半夜监控报警,订单系统重复扣款。查了半天,又是分布式锁没扛住并发。干了十年运维,这种坑见过太多,今天把 Redis 分布式锁实现里最要命的 3 个点拆清楚,别让你家系统也背锅。
坑一:SETNX 与 EXPIRE 非原子操作
很多新人喜欢把加锁和设过期时间分开写,这是找死。网络抖动导致设过期时间失败,锁就永不过期,死锁等着您。
# 错误示范
redis.setnx(lock_key, request_id)
redis.expire(lock_key, 30)
**效果说明:** 若第二句执行前服务崩溃,锁永久存在,后续请求全部阻塞,系统瘫痪。
坑二:单节点故障导致锁失效
单主 Redis 挂了,主从切换瞬间,锁可能还没同步到从库,新主认为锁不存在,并发瞬间击穿。这时候必须上 Lua 脚本保证原子性。
-- 正确示范:加锁与过期原子执行
if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then
return redis.call('expire', KEYS[1], ARGV[2])
else
return 0
end
**效果说明:** 脚本在 Redis 服务端原子执行,要么全成功,要么全失败,杜绝中间状态导致的锁泄露。
坑三:脑裂场景下的 Redlock 算法
高可用集群下,单锁不可靠。Redlock 算法要求客户端向 5 个独立节点申请锁,至少 3 个成功才算拿到锁,防止脑裂。
# Redlock 逻辑示意
success_count = 0
for node in redis_nodes:
if node.set(lock_key, val, nx=True, ex=30):
success_count += 1
if success_count >= 3:
return True # 锁获取成功
**效果说明:** 即使 2 个节点宕机或网络分区,只要多数派共识达成,锁依然安全,避免双主同时写入。
老兵避坑清单
-
**锁超时时间**:必须大于业务执行时间,防止业务没完锁已释放。
-
**解锁校验**:释放锁时校验 request_id,防止误删别人的锁。
-
**时钟漂移**:Redlock 需扣除网络耗时,避免客户端时间不准导致锁过早失效。
-
**重试机制**:获取锁失败需带退避策略重试,避免雪崩。
-
**看门狗**:业务耗时不确定时,用看门狗自动续期,别硬设超时。
分布式锁不是银弹,理解底层原理才能稳住生产。你在线上遇到过锁失效导致的脏数据吗?是怎么解决的?