为什么要有哨兵? | 小林coding (xiaolincoding.com)
哨兵(Sentinel)机制,它的作用是实现主从节点故障转移。它会监测主节点是否存活,如果发现主节点挂了,它就会选举一个从节点切换为主节点,并且把新主节点的相关信息通知给从节点和客户端。
哨兵其实是一个运行在特殊模式下的 Redis 进程,所以它也是一个节点,而且是没有存储能力的redis节点。
哨兵节点主要负责三件事情:监控、选主、通知。
- 哨兵节点是如何监控节点的?又是如何判断主节点是否真的故障了?
- 根据什么规则选择一个从节点切换为主节点?
- 怎么把新主节点的相关信息通知给从节点和客户端呢?
如何判断主节点故障
哨兵会每隔 1 秒给所有主从节点发送 PING 命令,当主从节点收到 PING 命令后,会发送一个响应命令给哨兵,这样就可以判断它们是否在正常运行。
主观下线和客观下线
如果主节点或者从节点没有在规定的时间内响应哨兵的 PING 命令,哨兵就会将它们标记为「主观下线」。这个「规定的时间」是配置项 down-after-milliseconds
参数设定的,单位是毫秒。
客观下线只适用于主节点。
为什么要区分客观下线?
可能「主节点」其实并没有故障,可能只是因为主节点的系统压力比较大或者网络发送了拥塞,导致主节点没有在规定时间内响应哨兵的 PING 命令。所以,为了减少误判的情况,哨兵在部署的时候不会只部署一个节点,而是用多个节点部署成哨兵集群(最少需要三台机器来部署哨兵集群),通过多个哨兵节点一起判断,就可以就可以避免单个哨兵因为自身网络状况不好,而误判主节点下线的情况。同时,多个哨兵的网络同时不稳定的概率较小,由它们一起做决策,误判率也能降低。
如何判断客观下线
当一个哨兵判断主节点为「主观下线」后,就会向其他哨兵发起命令,其他哨兵收到这个命令后,就会根据自身和主节点的网络状况,做出赞成投票或者拒绝投票的响应。
当这个哨兵的赞同票数达到哨兵配置文件中的 quorum 配置项设定的值后,这时主节点就会被该哨兵标记为「客观下线」。
例如,现在有 3 个哨兵,quorum 配置的是 2,那么一个哨兵需要 2 张赞成票,就可以标记主节点为“客观下线”了。这 2 张赞成票包括哨兵自己的一张赞成票和另外两个哨兵的赞成票。
选举Leader
哨兵是以哨兵集群的方式存在的,只有一个哨兵节点可以进行主从故障转移,因此需要在哨兵集群中选出一个 leader,让 leader 来执行主从切换。
选举 leader 的过程其实是一个投票的过程,在投票开始前,肯定得有个「候选者」。
候选者是哪些?
判断主节点为「客观下线」的哨兵节点就是候选者
如何选举成为Leader
候选者会向其他哨兵发送命令,表明希望成为 Leader 来执行主从切换,并让所有其他哨兵对它进行投票。
每个哨兵只有一次投票机会,如果用完后就不能参与投票了,可以投给自己或投给别人,但是只有候选者才能把票投给自己。(每位候选者都会先给自己投一票,然后向其他哨兵发起投票请求。)
那么在投票过程中,任何一个「候选者」,要满足两个条件:
- 第一,拿到半数以上的赞成票;
- 第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值。
举个例子,假设哨兵节点有 3 个,quorum 设置为 2,那么任何一个想成为 Leader 的哨兵只要拿到 2 张赞成票,就可以选举成功了。如果没有满足条件,就需要重新进行选举。
哨兵节点的数量和quorum值的设定
先说结论:哨兵节点至少要有3个,而且哨兵节点的数量应该是奇数,quorum 的值建议设置为哨兵个数的二分之一加1
关于哨兵节点的数量是奇数:便于哨兵通过投票做出“决策”,领导者选举的决策、客观下线的决策(找了一圈都是这么说,具体为什么也没想明白)
考虑如下情况:哨兵集群中只有 2 个哨兵节点,此时如果一个哨兵想要成功成为 Leader,必须获得 2 票,而不是 1 票。所以,如果哨兵集群中有个哨兵挂掉了,那么就只剩一个哨兵了,如果这个哨兵想要成为 Leader,这时票数就没办法达到 2 票,就无法成功成为 Leader,这时是无法进行主从节点切换的。
另一种情况:3 个哨兵节点,挂了 2 个怎么办?这个时候得人为介入了,或者增加多一点哨兵节点。
通过以下例子体会quorum和哨兵数量设置不同值的影响:Redis 1 主 4 从,5 个哨兵 ,quorum 设置为 3
1. 如果 2 个哨兵故障,当主节点宕机时,哨兵能否判断主节点“客观下线”?主从能否自动切换?
-
哨兵集群可以判定主节点“客观下线”。哨兵集群还剩下 3 个哨兵,当一个哨兵判断主节点“主观下线”后,询问另外 2 个哨兵后,有可能能拿到 3 张赞同票,这时就达到了 quorum 的值,因此,哨兵集群可以判定主节点为“客观下线”。
-
哨兵集群可以完成主从切换。当有个哨兵标记主节点为「客观下线」后,就会进行选举 Leader 的过程,因为此时哨兵集群还剩下 3 个哨兵,那么还是可以拿到半数以上(5/2+1=3)的票,而且也达到了 quorum 值,满足了选举 Leader 的两个条件, 所以就能选举成功,因此哨兵集群可以完成主从切换。
2. 如果 quorum 设置为 2 ,并且如果有 3 个哨兵故障的话。此时哨兵集群还是可以判定主节点为“客观下线”,但是哨兵不能完成主从切换了。
3. 如果 quorum 设置为 3,并且如果有 3 个哨兵故障的话,哨兵集群即不能判定主节点为“客观下线”,也不能完成主从切换了。
可以看到,quorum 为 2 的时候,并且如果有 3 个哨兵故障的话,虽然可以判定主节点为“客观下线”,但是不能完成主从切换,这样感觉「判定主节点为客观下线」这件事情白做了一样,既然这样,还不如不要做,quorum 为 3 的时候,就可以避免这种无用功。
主从故障转移
1. 选举新主节点
在已下线主节点属下的所有「从节点」中,挑选出一个状态良好、数据完整的从节点,然后向这个「从节点」发送 SLAVEOF no one 命令,将这个「从节点」转换为「主节点」。
- 过滤掉网络状况不佳的从节点。包括已下线的从节点和以往网络连接状态不好的从节点
如何判断从节点之前的网络连接状态不好?Redis 有个叫 down-after-milliseconds * 10 配置项,其down-after-milliseconds 是主从节点断连的最大连接超时时间。如果在 down-after-milliseconds 毫秒内,主从节点都没有通过网络联系上,我们就可以认为主从节点断连了。如果发生断连的次数超过了 10 次,就说明这个从节点的网络状况不好,不适合作为新主节点。
- 哨兵首先会根据从节点的优先级来进行排序,优先级越小排名越靠前
Redis 有个叫 slave-priority 配置项,可以给从节点设置优先级。每一台从节点的服务器配置不一定是相同的,我们可以根据服务器性能配置来设置从节点的优先级。
- 如果优先级相同,则查看复制的下标,哪个从「主节点」接收的复制数据多,哪个就靠前。
如果某个从节点的 slave_repl_offset 最接近 master_repl_offset,说明它的复制进度是最靠前的,于是就可以将它选为新主节点。
- 第三轮考察:如果优先级和下标都相同,就选择从节点 ID 较小的那个。
在选举出从节点后,哨兵 leader 向被选中的从节点发送 SLAVEOF no one
命令,让这个从节点解除从节点的身份,将其变为新主节点。
在发送 SLAVEOF no one
命令之后,哨兵 leader 会以每秒一次的频率向被升级的从节点发送 INFO
命令(没进行故障转移之前,INFO
命令的频率是每十秒一次),并观察命令回复中的角色信息,当被升级节点的角色信息从原来的 slave 变为 master 时,哨兵 leader 就知道被选中的从节点已经顺利升级为主节点了。
2. 将从主节点指向新主节点
哨兵 leader 向所有从节点(server3和server4)发送 SLAVEOF
,让它们成为新主节点的从节点。
3. 通知客户端主节点已更换
通过 Redis 的发布者/订阅者机制来实现的。每个哨兵节点提供发布者/订阅者机制,客户端可以从哨兵订阅消息。
客户端和哨兵建立连接后,客户端会订阅哨兵提供的频道。主从切换完成后,哨兵就会向 +switch-master
频道发布新主节点的 IP 地址和端口的消息,这个时候客户端就可以收到这条信息,然后用这里面的新主节点的 IP 地址和端口进行通信了。
4. 将旧主节点变为从节点
继续监视旧主节点,当旧主节点重新上线时,哨兵集群就会向它发送 SLAVEOF
命令,让它成为新主节点的从节点
哨兵集群
哨兵节点之间是通过 Redis 的发布者/订阅者机制来相互发现的。
在主从集群中,主节点上有一个名为__sentinel__:hello
的频道,不同哨兵就是通过它来相互发现,实现互相通信的。
在下图中,哨兵 A 把自己的 IP 地址和端口的信息发布到__sentinel__:hello
频道上,哨兵 B 和 C 订阅了该频道。那么此时,哨兵 B 和 C 就可以从这个频道直接获取哨兵 A 的 IP 地址和端口号。然后,哨兵 B、C 可以和哨兵 A 建立网络连接。
通过这个方式,哨兵 B 和 C 也可以建立网络连接,这样一来,哨兵集群就形成了。
哨兵集群如何知道「从节点」的信息?
主节点知道所有「从节点」的信息,所以哨兵会每 10 秒一次的频率向主节点发送 INFO 命令来获取所有「从节点」的信息。
如下图所示,哨兵 B 给主节点发送 INFO 命令,主节点接受到这个命令后,就会把从节点列表返回给哨兵。接着,哨兵就可以根据从节点列表中的连接信息,和每个从节点建立连接,并在这个连接上持续地对从节点进行监控。哨兵 A 和 C 可以通过相同的方法和从节点建立连接。
总结
哨兵(Sentinel)机制,它的作用是实现主从节点故障转移。它会监测主节点是否存活,如果发现主节点挂了,它就会选举一个从节点切换为主节点,并且把新主节点的相关信息通知给从节点和客户端。
哨兵一般是以集群的方式部署,至少需要 3 个哨兵节点,哨兵集群主要负责三件事情:监控、选主、通知。
哨兵节点通过 Redis 的发布者/订阅者机制,哨兵之间可以相互感知,相互连接,然后组成哨兵集群,同时哨兵又通过 INFO 命令,在主节点里获得了所有从节点连接信息,于是就能和从节点建立连接,并进行监控了。
1、第一轮投票:判断主节点下线
当哨兵集群中的某个哨兵判定主节点下线(主观下线)后,就会向其他哨兵发起命令,其他哨兵收到这个命令后,就会根据自身和主节点的网络状况,做出赞成投票或者拒绝投票的响应。
当这个哨兵的赞同票数达到哨兵配置文件中的 quorum 配置项设定的值后,这时主节点就会被该哨兵标记为「客观下线」。
2、第二轮投票:选出哨兵leader
某个哨兵判定主节点客观下线后,该哨兵就会发起投票,告诉其他哨兵,它想成为 leader,想成为 leader 的哨兵节点,要满足两个条件:
- 第一,拿到半数以上的赞成票;
- 第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值。
3、由哨兵 leader 进行主从故障转移
选举出了哨兵 leader 后,就可以进行主从故障转移的过程了。该操作包含以下四个步骤:
- 第一步:在已下线主节点(旧主节点)属下的所有「从节点」里面,挑选出一个从节点,并将其转换为主节点,选择的规则:
- 过滤掉已经离线的从节点;
- 过滤掉历史网络连接状态不好的从节点;
- 将剩下的从节点,进行三轮考察:优先级、复制进度、ID 号。在每一轮考察过程中,如果找到了一个胜出的从节点,就将其作为新主节点。
- 第二步:让已下线主节点属下的所有「从节点」修改复制目标,修改为复制「新主节点」;
- 第三步:将新主节点的 IP 地址和信息,通过「发布者/订阅者机制」通知给客户端;
- 第四步:继续监视旧主节点,当这个旧主节点重新上线时,将它设置为新主节点的从节点;