记一次Redis分布式锁实现线上排查:Redlock算法与 Lua 脚本

<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 个节点宕机或网络分区,只要多数派共识达成,锁依然安全,避免双主同时写入。

老兵避坑清单

  1. **锁超时时间**:必须大于业务执行时间,防止业务没完锁已释放。

  2. **解锁校验**:释放锁时校验 request_id,防止误删别人的锁。

  3. **时钟漂移**:Redlock 需扣除网络耗时,避免客户端时间不准导致锁过早失效。

  4. **重试机制**:获取锁失败需带退避策略重试,避免雪崩。

  5. **看门狗**:业务耗时不确定时,用看门狗自动续期,别硬设超时。

分布式锁不是银弹,理解底层原理才能稳住生产。你在线上遇到过锁失效导致的脏数据吗?是怎么解决的?

相关推荐
轮子大叔2 小时前
Redis深入浅出
redis·缓存
计算机就业还在扩大2 小时前
Redis中的setnx是原子性的?
数据库·redis·缓存
Java爱好狂.5 小时前
Java小白如何三天速通redis?
java·数据库·redis·架构师·分布式锁·java面试·java程序员
一条泥憨鱼21 小时前
【Redis | 黑马点评】短信登录功能 源码深度分析
java·redis·后端·session·黑马点评
m0_752035631 天前
Redis 数据结构总结
数据结构·数据库·redis
guo_wen_qiang1 天前
redis持久化
数据库·redis·分布式
我命由我123451 天前
LRU 缓存淘汰策略
数据结构·redis·学习·mysql·算法·缓存·学习方法
十年Java程序媛1 天前
Redis 分布式锁 + GZIP 压缩缓存踩坑|高并发缓存真实线上复盘
java·开发语言·spring boot·redis·分布式·缓存·面试
凤山老林1 天前
Spring Boot 集成 Redis ZSet 实现实时排行榜、动态排名、同分加权与多维度榜单实战
spring boot·redis·后端