主库突然挂了,集群要多久才能恢复写入?这个问题的答案不是「秒级」这种模糊说法,而是一串有先后的事件:怀疑、确认、选举、升主。这篇真的 kill -9 一个主库,让两个写线程一直写着,把每个事件发生的毫秒数量出来,连做三次。
每次实验起一个新的 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 回读,检查是否丢失。重复三次。
第 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(3 s)没回应,单方面标记「可能失败」。这是整个窗口里最长的一段,也是唯一直接由这个配置决定的一段。所以不可用窗口大约是 cluster-node-timeout 的 1.8 倍;调小 timeout 能缩短窗口,代价是网络抖动时更容易误判(这个取舍我没有实验)。
三次实验共 1307 次已确认的写入(每个 key 最后一次成功的值),回读全部命中,新主库上丢失 0 个、值落后的 0 个。但这不是保证:Redis 复制是异步的,主库回复客户端时不等从库确认,理论上刚写入、还没同步到从库就被 kill 的那几条会丢。我的写线程每 3 ms 写一次、被 kill 的瞬间恰好没有遗留待同步的数据,所以 3 次都没撞上。想量这个窗口需要更高的写入压力,见第 93 篇。