bigywater.tech
Redis · 88

Sentinel 故障转移投票

上一篇里 quorum 决定「客观下线」。但真正执行故障转移,要在 sentinel 里选出一个领导者,这需要「多数 sentinel」投票——不是 quorum。两件事经常被混为一谈。这篇订阅 sentinel 的事件流,把两个 sentinel 抢着当领导者的过程和「凑不够多数」的失败都抓下来。

2 / 3
sentinel0 当选所需与得到的票数(每个 sentinel 每个 epoch 只投一票)
quorum 1 也不行
o_down 成立,但只有 1 个 sentinel 可用时拿不到多数,故障转移放弃
12.1 s
failover-timeout 8000 ms 下,选举失败后 -failover-abort-not-elected 的时间

两个候选人

订阅 sentinel 的 PSUBSCRIBE * 事件流(时间相对 kill -9 主库)
实测 · 本机执行输出
+  3177 ms  s0  +odown               master mymaster 127.0.0.1 7740 #quorum 3/2
+  3177 ms  s0  +new-epoch           1
+  3177 ms  s0  +try-failover        master mymaster 127.0.0.1 7740
+  3177 ms  s0  +vote-for-leader     4570effe484f7513910e9464e58a0cad40caeec2 1
+  3179 ms  s2  +odown               master mymaster 127.0.0.1 7740 #quorum 2/2
+  3179 ms  s2  +new-epoch           1
+  3179 ms  s2  +try-failover        master mymaster 127.0.0.1 7740
+  3179 ms  s2  +vote-for-leader     59ffdbdd56a9a3d80a8028ef42b76862d0a29d8d 1
+  3185 ms  s1  +new-epoch           1
+  3185 ms  s1  +vote-for-leader     4570effe484f7513910e9464e58a0cad40caeec2 1
+  3256 ms  s0  +elected-leader      master mymaster 127.0.0.1 7740
+  4178 ms  s1  +odown               master mymaster 127.0.0.1 7740 #quorum 3/2

quorum 2 时,sentinel0 和 sentinel2 几乎同时(相差 2 ms)达成 o_down 并 +try-failover,都在 epoch 1。+vote-for-leader 的参数是被投票 sentinel 的 ID 和 epoch:sentinel0(4570effe…)得 2 票(自己和 sentinel1),sentinel2(59ffdbdd…)只有自己 1 票。得到多数(3 个里的 2 个)的 sentinel0 +elected-leader,然后由它选新主库、发 SLAVEOF NO ONE(第 89 篇)。

凑不够多数

quorum 1,另两个 sentinel 冻结
实测 · 本机执行输出
  +  3070 ms  +sdown                             master mymaster 127.0.0.1 7780
  +  3070 ms  +odown                             master mymaster 127.0.0.1 7780 #quorum 1/1
  +  3070 ms  +new-epoch                         1
  +  3070 ms  +try-failover                      master mymaster 127.0.0.1 7780
  +  3070 ms  +vote-for-leader                   931518641f7bc88ba3f11ea6ace191ec540cd281 1
  +  3440 ms  +sdown                             sentinel d161c491bf8a9952383e7aaa5902b9699c418277 127.0.0.1 7802 @ mymaster 127.
  +  3440 ms  +sdown                             sentinel d76a1f43855c438140b1823d1f5d91f3b1b76f52 127.0.0.1 7801 @ mymaster 127.
  + 12055 ms  -failover-abort-not-elected        master mymaster 127.0.0.1 7780
  + 20029 ms  +new-epoch                         2
  + 20029 ms  +try-failover                      master mymaster 127.0.0.1 7780
  + 20029 ms  +vote-for-leader                   931518641f7bc88ba3f11ea6ace191ec540cd281 2
  25 秒后 sentinel0 认为的主库地址: ('127.0.0.1', 7780) (仍是旧主库:没有选出新主库)
  主库仍是 7780 的 flags: s_down,o_down,master,disconnected,failover_in_progress
  sentinel0 日志(节选):
    +try-failover master mymaster 127.0.0.1 7780
    +vote-for-leader 931518641f7bc88ba3f11ea6ace191ec540cd281 1
    -failover-abort-not-elected master mymaster 127.0.0.1 7780
    15812:X 30 Sep 2026 02:08:46.917 * Next failover delay: I will not start a failover before Wed Sep 30 02:08:54 2026
    +try-failover master mymaster 127.0.0.1 7780
    +vote-for-leader 931518641f7bc88ba3f11ea6ace191ec540cd281 2

即使 quorum 设成 1,让单个 sentinel 就能宣布客观下线,执行故障转移仍需要多数 sentinel 授权:只有 1 个可用时,它给自己投了一票,但 3 个里需要 2 票。超时后放弃(-failover-abort-not-elected),冷却一段时间后用更大的 epoch 再试,仍然失败。日志里的 Next failover delay: I will not start a failover before … 就是这个冷却时间。

实践含义

部署 sentinel 至少要 3 个且放在不同的故障域里:主库挂掉的同时如果有 sentinel 一起不可用,剩下的 sentinel 数必须仍然超过一半,否则即使检测到了故障也切不了。

分步演示:选举

Sentinel 故障转移投票
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。3 个 sentinel,quorum 2(第一组)与 quorum 1 + 两个 sentinel 冻结(第二组,failover-timeout 8000);事件来自 PSUBSCRIBE *
    • 没有验证:sentinel 数量为 5 时的多数(3)、选举 epoch 冲突时的多轮结果、跨机器时钟差的影响
    京ICP备2026067502号-1京公网安备11010502063487号