bigywater.tech
Redis · 75

Redis Cluster 故障转移

主库突然挂了,集群要多久才能恢复写入?这个问题的答案不是「秒级」这种模糊说法,而是一串有先后的事件:怀疑、确认、选举、升主。这篇真的 kill -9 一个主库,让两个写线程一直写着,把每个事件发生的毫秒数量出来,连做三次。

3652 → 4645 → 5378 ms
kill 后 PFAIL → FAIL → 从库升主(中位数)
约 5.4 s
该主库的槽上写入恢复所需时间(cluster-node-timeout 的 1.8 倍)
0 / 1307
已确认写入在新主库上丢失的个数(3 次实验)

做法

每次实验起一个新的 3 主 3 从集群(cluster-node-timeout 3000)。两个写线程各自用集群客户端不停 SET,每次间隔 3 ms:线程 X 只写将被杀掉的主库负责的槽,线程 Y 写另一个主库的槽。1 秒后对 X 主库 kill -9,同时每 10 ms 读一次三个幸存节点的 CLUSTER NODES,记录被杀节点何时被标 fail?(PFAIL)、何时变 fail、它的从库何时变成 master。结束后把线程 X 确认过的每一个 key 回读,检查是否丢失。重复三次。

三次实验的事件时间线

时间是 kill 之后的毫秒数;「写入恢复」是线程 X 最后一次报错之后第一次成功的时间
实测 · 本机执行输出
第 1 次:kill 后  PFAIL    3934 ms  FAIL    4645 ms  从库升主    5378 ms  写入恢复    5439 ms   |  X 槽写入错误 10 次  其它槽写入错误 1 次  |  已确认写入 432,新主库上丢失 0,落后(旧值)0
第 2 次:kill 后  PFAIL    3652 ms  FAIL    4224 ms  从库升主    5026 ms  写入恢复    5027 ms   |  X 槽写入错误 9 次  其它槽写入错误 1 次  |  已确认写入 440,新主库上丢失 0,落后(旧值)0
第 3 次:kill 后  PFAIL    3344 ms  FAIL    4761 ms  从库升主    5586 ms  写入恢复    5616 ms   |  X 槽写入错误 11 次  其它槽写入错误 1 次  |  已确认写入 435,新主库上丢失 0,落后(旧值)0

从库的日志(第 3 次):
   FAIL message received from da26c58f7c63f07a99b5476f3e13b25ca793b670 () about f4fc320c16eb1894202daf66dbb624dbf32f2ebb ()
   Start of election delayed for 517 milliseconds (rank #0, offset 7171).
   Starting a failover election for epoch 7.
   Failover election won: I'm the new master.

三次结果比较一致:PFAIL 3344–3934 ms,FAIL 4224–4761 ms,升主 5026–5586 ms,写入恢复与升主几乎同时。X 槽上的写线程每次遇到 9–11 次错误;另一个写线程的槽在这一过程中出现过 1 次瞬时错误(我没有追查这一次错误的具体原因,重复三次都是 1 次)。

每个阶段在等什么

所以不可用窗口大约是 cluster-node-timeout 的 1.8 倍;调小 timeout 能缩短窗口,代价是网络抖动时更容易误判(这个取舍我没有实验)。

已确认的写入丢了吗

三次实验共 1307 次已确认的写入(每个 key 最后一次成功的值),回读全部命中,新主库上丢失 0 个、值落后的 0 个。但这不是保证:Redis 复制是异步的,主库回复客户端时不等从库确认,理论上刚写入、还没同步到从库就被 kill 的那几条会丢。我的写线程每 3 ms 写一次、被 kill 的瞬间恰好没有遗留待同步的数据,所以 3 次都没撞上。想量这个窗口需要更高的写入压力,见第 93 篇。

分步演示:一次故障转移的时间线

Redis Cluster 故障转移
本步的事件

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。每次一个新的 3 主 3 从集群;kill -9 只杀主库进程(操作系统与网络正常),TCP 连接立刻被重置;时间取自我的采样脚本(10 ms 间隔),每个数字有约 10–20 ms 的观测误差
    • 没有验证:「PFAIL 升级为 FAIL 需要多数主库同意」是官方的设计说明,本文只观察到了 PFAIL→FAIL 的时间间隔,没有单独验证投票数;网络分区(而非进程被杀)下的时间线(第 83 篇)、cluster-node-timeout 取其它值时的关系、多个从库时的选举顺序(rank)、高写入压力下的数据丢失窗口、Linux 上的表现
    京ICP备2026067502号-1京公网安备11010502063487号