连载中 7/20

主从切换下的锁失效:异步复制的原罪

2026-06-28 · 4683 阅读 · 0 评论 · 0 赞

一条完整的事故时间线

Redis 部署成主从加哨兵(Sentinel)是标配:主库扛写,从库兜底,主库挂了哨兵自动提升从库。一切正常时天下太平,直到某一秒,四个动作撞在了一起:

t0    客户端A 向主库 M 发 SET lock 8f3a NX PX 10000 → OK,A 拿到锁
t0+1ms 主库 M 宕机,lock 这条写还没来得及复制给从库 S
t0+30s 哨兵仲裁完成,S 升级为新主库
t0+31s 客户端B 连新主库 SET lock ... NX PX → OK(key 在新主上不存在)
      ↑ A 和 B 同时「持有」锁,临界区里出现了两个人

注意 A 并没有做错任何事:它按规矩抢锁、按规矩干活,锁丢在主从异步复制这个它根本控制不了的环节上。A 拿锁期间如果又崩又复活(第 5 篇的 GC 场景),连「感知丢锁」的机会都没有。这就是 Redis 锁最被诟病的一击,也是 Martin 批评 RedLock 时的核心论据——只要锁的持久性依赖异步复制,主从切换就永远是锁的真空时刻。这不是配置能根治的:Redis 为了写性能选择了异步复制,性能与安全的天平在架构上就已倾斜。

缓解一:min-replicas 限写

antirez 官方建议的止血方案是两个参数:

min-replicas-to-write 1     # 至少 1 个从库在线才接受写入
min-replicas-max-lag 10     # 且该从库复制延迟不超过 10 秒

思路是「与其发一把可能丢失的锁,不如不发」:主库检测到没有任何健康的从库(延迟超限)就拒绝写锁请求,抢锁的客户端直接失败。故障切换的窗口被压缩了——从「主挂了锁还在飞」变成「主挂了锁服务先停摆,新主起来再恢复」。安全性上有所改善,代价是可用性:从库抖动会连带锁服务不可用,业务要能接受「Redis 不可用时拿不到锁」的降级路径(排队、本地限流、或直接拒绝)。

缓解二:WAIT 与它的不严格

Redis 3.0 起提供了 WAIT 命令:SET 写锁成功后跟一条 WAIT 1 100(等 1 个从库确认、最多等 100 毫秒),看起来是同步复制语义。但要交底清楚:WAIT 只保证写入已进入从库的复制流,不保证从库已完成落盘,更不保证 failover 后的完整链路——WAIT 返回后主库立刻宕机,极端情况下从库升主时那条锁记录依然可能丢。WAIT 把丢锁概率从「毫秒窗口」压到「极小概率」,但压不到零,它的每一点改善都在吃写延迟。真要严格同步复制,Redis 给不了,这是定位问题不是参数问题。

Redis 锁的诚实交底

到这里,Redis 锁的底牌全部亮完,可以给它下结论了:Redis 锁是效率锁的王者,是正确性锁的赌徒。快(内存操作)、轻(不引入新组件)、生态好(Redisson 全家桶),防重复跑、防缓存击穿、防重复建单这类「双跑浪费但不致命」的场景闭眼用。但碰钱、碰库存、碰任何「双跑即事故」的场景,单靠它就是赌——要么赌主从切换不撞上临界区(多数时候能赢),要么配上 fencing token 兜底(第 16 篇),要么换一把「天生为一致而生」的锁。第 5 篇那张选型表的最后一行,就是接下来四篇的主角:ZooKeeper——一个把「所有节点对同一件事达成一致」写进设计目标、用 ZAB 协议背书的协调服务。下一篇先补齐它的基础课:ZNode、Watch、临时节点,三个概念撑起它的全部精彩。

Cluster 分片:同一出戏演 N 遍

有人会想:换成 Redis Cluster 是不是就好了?答案是原样重演。Cluster 只是把数据按 slot 分片到多个主从组,每一把锁落在某个 slot 上,就只归那一个分片的主库管——每个分片内部依然是异步复制的主从结构,主从切换时丢锁的窗口一秒都没少。分片多反而让「哪把锁在哪片」的心智负担更重。一句话总结 Redis 锁的复制观:单机、哨兵、Cluster,三种架构三种壳,异步复制的芯一模一样。要跟这种原罪正面硬刚,只能靠 RedLock 的多数派、或下一篇登场的 ZAB 与 Raft 这类真协议。

503

10 年全栈工程师 · 503咖啡馆主理人

#分布式锁#主从切换#异步复制#哨兵#min-replicas#丢失锁

评论 (0)

相关推荐

连载中 12/20

排查四件套:jstack、jmap、jstat、jcmd 的实战分工

jstack 看线程在干什么,jmap 看堆里装了什么,jstat 看运行时在变什么,jcmd 是统一入口。四把刀各管一段,配合着用没有查不动的现场。

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 4 阅读 · 0 评论 · 0 赞
连载中 11/20

GC 日志:把回收过程翻译成人话

一行 GC 日志里塞着七种信息:谁触发的、收了哪、停了多久、活了哪些。加上 -Xlog 配置,再加上日志分析工具,GC 不再是只能盯监控曲线的黑盒。

#GC日志#Xlog#日志分析#GC监控#Full GC排查
2026-09-16 · 13 阅读 · 0 评论 · 0 赞
连载中 10/20

ZGC:亚毫秒停顿是怎么炼成的

百 G 大堆停顿不到一毫秒,靠的是把搬家全部挪到并发阶段——着色指针让引用自带状态,读屏障让搬运中的对象依然可访问。代价是吞吐与内存,收益是停顿与堆大小解耦。

#ZGC#着色指针#读屏障#亚毫秒停顿#分代ZGC
2026-09-15 · 8 阅读 · 0 评论 · 0 赞