概述
本文主要讲述了Redis故障转移的原理及过程,可与「Redis高可用架构」文章一同阅读,可更好理解相关内容,及整个Redis高可用架构的实现原理。
Leader 选举
哨兵首先进入 WATI_START
状态进行准备,等待哨兵成为哨兵集群的 Leader 才有资格进行故障转移。如果在超时时间之内哨兵都没有成为 Leader,则哨兵会调用 sentinelAbortFailover()
函数并结束本次故障转移。
当哨兵想要进行故障转移,首先需要得到多数哨兵的支持才能进行。而且,同一时间可能会有多个哨兵发起故障转移,所以故障转移前需要进行一轮竞选,得到多数选票的哨兵会被称为 Leader,只有 Leader 才能进行故障转移。
选举原理
Redis 的 Leader 选举使用的是 Raft 算法,因此 Leader 选举的流程是相同的,具体可见:【分布式】Raft 算法 - Leader 选举。
哨兵属性
根据 Raft 算法,每个哨兵需要存储两个信息,是当前任期和心仪候选人,在 Redis 定义为 current_epoch
和 leader
,leander
字段用于存储心仪候选人的 runId
。
投票请求
同时,哨兵的投票请求依旧沿用 SENTINEL is-master-down-by-addr
指令,但此时除了附上自己的 Epoch 之外,还会在参数中带上自己的 runId
,标志投票的发起人。如:
SENTINEL is-master-down-by-addr 172.26.0.101 6379 4 9effe0cdc338e245391055caa45a05adf61fed37
投票方法
根据 Raft 算法,哨兵的投票原则就是:leader
字段是谁的 ID,就投给谁。
- 当哨兵要参加竞选,就会将自己的
current_epoch
字段加一,并将leader
字段指向自己。- 当哨兵接收到投票请求,如果请求的
epoch
小于等于哨兵自身的current_epoch
,就投给自己leader
字段所指的哨兵。如果大于自身的current_epoch
,就将更新自己的leader
字段为请求中的runId
,再将票投给对方。- 根据第一点和第二点,如果竞选哨兵收到了其他哨兵的投票请求,此时对方
epoch
与自己相等,永远都只会投给自己。
因此,同一轮 Epoch 的竞选中,不参选的哨兵会一直投给第一个发给它请求的哨兵。参选的哨兵会一直投给自己。这样,保证了同一轮 Epoch 竞选中,每个投票人只能投给一个人,保证了投票的正确性和公平性。
选举过程
总结哨兵的具体选举过程为:
- 哨兵确认主节点
odown
后,将自身current_epoch
加一,将leader
指向自己,并向其他哨兵发送投票请求。- 其他哨兵接收到投票请求,判断请求中的
epoch
是否大于自己的current_epoch
: 大于则更新current_epoch
并将leader
指向发送方,然后投票给发送方。 小于或等于则将票投给自己leader
字段指向的哨兵(可能是它自己)。- 哨兵每收到一个回复就会将对方的投票结果存储起来,并累计自己的得票数(投给自己的选票数加一,算上自己),当自己得票数超一半且不小于
quorum
时,成为 Leader 并向所有哨兵公示投票结果。- 如果到投票计时截止,哨兵自身的累计票数还没达标,哨兵就会宣告竞选失败,并进入一段随机的等待时间,等待结束之后会再次进行选举。
- 落选可能是有其他人当选,也可能没人能达标,当哨兵不关心有没有人胜选,因为如果有晋级者,它会主动宣告成功的。
- 在等待期间如果没有任何哨兵宣布胜选,则等待时间结束后,哨兵会重新进行选举,此时回到步骤 1。
Master 选取
当选 Leader 后哨兵会进入 SELECT_SLAVE
状态,选取新的主节点。
选取新的主节点遵守以下规则:
排除:
- 已下线的从节点(
sdown
、odown
)。 - 连接断开的节点(
PING
超时,disconnected
状态)。 - 配置了不当 Master 的节点(
replica-priority = 0
)。 - 与宕机主节点断开时间过长的从节点(超 10 倍
down-after-milliseconds
)。
- 已下线的从节点(
优先级,从高到低排序:
- 优先值最高的节点(
replica-priority
最小)。 - 复制偏移量最大的节点。
- 配置了
runId
的节点。 - 随机
runId
字典序最小的节点。
- 优先值最高的节点(
如果选取失败,会隔一段时间进行重试,直到选取出新的主节点为止。
Slave 身份去除
当确定新的主节点后,哨兵会进入 SEND_SLAVEOF_NOONE
状态,撤销该节点的 Slave 状态。
1:X 19 Aug 2021 08:30:07.587 * +failover-state-send-slaveof-noone slave 172.25.0.102:6379 172.25.0.102 6379 @ mymaster 172.25.0.101 6379
哨兵会发送 slaveof NO ONE
指令给从节点,从节点接收到后会断开它与原主节点的网络连接,重置其复制 ID 并执行持久化重写,并开始将自己的复制身份转为 Master。
提升 Master
在发送指令之后,哨兵会进入 WAIT_PROMOTION
状态,等待该节点将自己提升为主节点。
1:X 19 Aug 2021 08:30:07.679 * +failover-state-wait-promotion slave 172.25.0.102:6379 172.25.0.102 6379 @ mymaster 172.25.0.101 6379
等待过程中哨兵会每隔一秒发送一次 INFO
命令给它,直到它的角色变成 Master。
配置从节点
当节点提升为 Master 之后,哨兵会进入 RECONF_SLAVES
状态,更新所有从节点的配置,让他们去复制新的 Master。
1:X 19 Mar 2024 13:30:08.374 # +promoted-slave slave 172.25.0.102:6379 172.25.0.102 6379 @ mymaster 172.25.0.101 6379
1:X 19 Mar 2024 13:30:08.374 # +failover-state-reconf-slaves master mymaster 172.25.0.101 6379
哨兵通过向从节点发送 slaveof <ip> <port>
命令即可修改从节点复制配置,并让从节点去复制新的主节点。