跳至主要內容

Redis-高可用篇-②哨兵模式

holic-x...大约 20 分钟RedisRedis

Redis-高可用篇-②哨兵模式

学习核心

  • 理解哨兵的目的和实现
    • 为什么要有哨兵机制?
    • 哨兵机制的实现(工作流程)
    • 主从故障概念核心
    • 哨兵集群

学习资料

哨兵机制

1.哨兵机制核心

哨兵机制的引入

​ 在Redis的主从架构中,由于主从模式是读写分离的,如果主节点(master)挂了,那么将没有主节点来服务客户端的写操作请求,也没有主节点给从节点(slave)进行数据同步了。这时如果要恢复服务的话,需要人工介入,选择一个「从节点」切换为「主节点」,然后让其他从节点指向新的主节点,同时还需要通知上游那些连接 Redis 主节点的客户端,将其配置中的主节点 IP 地址更新为「新主节点」的 IP 地址,但这种实现并不“智能”。要是有一个节点能监控「主节点」的状态,当发现主节点挂了,它自动将一个「从节点」切换为「主节点」的话,这个过程将会简化很多。

​ Redis 在 2.8 版本以后提供的哨兵(Sentinel)机制,它的作用是实现主从节点故障转移。它会监测主节点是否存活,如果发现主节点挂了,它就会选举一个从节点切换为主节点,并且把新主节点的相关信息通知给从节点和客户端

哨兵机制的实现(工作流程):监控、选主、通知

​ 哨兵其实是一个运行在特殊模式下的 Redis 进程,所以它也是一个节点。结合"哨兵"这一名词可知,它相当于是“观察者节点”,观察的对象是主从节点。在它观察到有异常的状况下,还会做出一些“动作”,来修复异常状态。

​ 哨兵节点主要负责三件事情:监控、选主、通知,基于此从下面几个方面来进一步掌握哨兵机制的工作流程:核心在于分析哨兵节点如何监听节点并实现主从故障转移

  • 哨兵节点是如何监控节点的?又是如何判断主节点是否真的故障了?
  • 根据什么规则选择一个从节点切换为主节点?
  • 怎么把新主节点的相关信息通知给从节点和客户端呢?

2.哨兵机制工作流程

🏐如何判断主节点真的故障?(主观下线、客观下线)

​ 哨兵会每隔 1 秒给所有主从节点发送 PING 命令,当主从节点收到 PING 命令后,会发送一个响应命令给哨兵,这样就可以判断它们是否在正常运行。如果主节点或者从节点没有在规定的时间内响应哨兵的 PING 命令,哨兵就会将它们标记为「主观下线」。这个「规定的时间」是配置项 down-after-milliseconds 参数设定的,单位是毫秒。

主观下线 VS 客观下线

​ 之所以针对「主节点」设计「主观下线」和「客观下线」两个状态,是因为有可能「主节点」其实并没有故障,可能只是因为主节点的系统压力比较大或者网络发送了拥塞,导致主节点没有在规定时间内响应哨兵的 PING 命令。

​ 所以,为了减少误判的情况,哨兵在部署的时候不会只部署一个节点,而是用多个节点部署成哨兵集群最少需要三台机器来部署哨兵集群),通过多个哨兵节点一起判断,就可以就可以避免单个哨兵因为自身网络状况不好,而误判主节点下线的情况。同时,多个哨兵的网络同时不稳定的概率较小,由它们一起做决策,误判率也能降低。

客观下线只适用于主节点:当一个哨兵判断主节点为「主观下线」后,就会向其他哨兵发起命令,其他哨兵收到这个命令后,就会根据自身和主节点的网络状况,做出赞成投票或者拒绝投票的响应

image-20240720091743880

​ 当这个哨兵的赞同票数达到哨兵配置文件中的 quorum 配置项设定的值后,这时主节点就会被该哨兵标记为「客观下线」。quorum 的值一般设置为哨兵个数的二分之一加 1(例如 3 个哨兵就设置 2)

​ 例如,现在有 3 个哨兵,quorum 配置的是 2,那么一个哨兵需要 2 张赞成票,就可以标记主节点为“客观下线”了。这 2 张赞成票包括哨兵自己的一张赞成票和另外两个哨兵的赞成票。

🏐如何实现主从故障转移?

(1)由哪个哨兵进行主从故障转移?

​ 基于上述分析,为了更加"客观"判断主节点真的故障,一般不会只由单个哨兵的检测结果来进行判断,而是基于哨兵集群的多个哨兵一起判断以减少误判概率。

候选者

哪个哨兵节点判断主节点为「客观下线」,则其就是候选者,所谓的候选者就是想当 Leader 的哨兵。

​ 基于上述案例,当哨兵 B 先判断到主节点「主观下线后」,就会给其他实例发送 is-master-down-by-addr 命令。随后其他哨兵会根据自己和主节点的网络连接情况,做出赞成投票或者拒绝投票的响应。当哨兵 B 收到赞成票数达到哨兵配置文件中的 quorum 配置项设定的值后,就会将主节点标记为「客观下线」,此时的哨兵 B 就是一个 Leader 候选者

候选者如何选举成为哨兵Leader

​ 候选者会向其他哨兵发送命令,表明希望成为 Leader 来执行主从切换,并让所有其他哨兵对它进行投票。每个哨兵只有一次投票机会,如果用完后就不能参与投票了,可以投给自己或投给别人,但是只有候选者才能把票投给自己。那么在投票过程中,任何一个「候选者」,要满足两个条件:如果没有满足条件,就需要重新进行选举

  • 条件1:拿到半数以上的赞成票;
  • 条件2:拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值;

​ 如果某个时间点,刚好有多个哨兵节点判断到主节点为客观下线,那这时不就有多个候选者了?这时该如何决定谁是 Leader 呢?每个哨兵只有一次投票机会,优先者满足条件者获胜

​ 每位候选者都会先给自己投一票,然后向其他哨兵发起投票请求。如果投票者先收到「候选者 A」的投票请求,就会先投票给它,如果投票者用完投票机会后,收到「候选者 B」的投票请求后,就会拒绝投票。此时就看哪位候选者先满足了上面的两个条件,其就会被选举为 Leader。

为什么哨兵节点要有至少要有3个?=》从判定客观下线、主从切换两个方面需要的条件进行考虑

​ 可以举例分析,如果哨兵节点只有2个的情况下能否正常完成操作?

​ 如果哨兵集群中只有 2 个哨兵节点,此时如果一个哨兵想要成功成为 Leader,必须获得 2 票,而不是 1 票(如果是1票的话也包括自己投的1票就失去客观判断的意义了)。所以,如果哨兵集群中有个哨兵挂掉了,那么就只剩一个哨兵了,如果这个哨兵想要成为 Leader,这时票数就没办法达到 2 票,就无法成功成为 Leader,这时是无法进行主从节点切换的。

​ 因此,通常至少会配置 3 个哨兵节点。这时,如果哨兵集群中有个哨兵挂掉了,那么还剩下两个哨兵,如果这个哨兵想要成为 Leader,这时还是有机会达到 2 票的,所以还是可以选举成功的,不会导致无法进行主从节点切换。如果往极端方向看,3个哨兵节点中挂了2个的话,则不得不进行人为介入了,或者增加多一点哨兵节点。

​ Redis 1 主 4 从,5 个哨兵,quorum 设置为 3,如果 2 个哨兵故障,当主节点宕机时,哨兵能否判断主节点“客观下线”?主从能否自动切换?

  • 哨兵集群可以判定主节点“客观下线”:哨兵集群还剩下 3 个哨兵,当一个哨兵判断主节点“主观下线”后,询问另外 2 个哨兵后,有机会拿到 3 张赞同票(则达到 quorum 的值),因此哨兵集群可以判定主节点为“客观下线”
  • 哨兵集群可以完成主从切换:当有个哨兵标记主节点为「客观下线」后,就会进行选举 Leader 的过程,因为此时哨兵集群还剩下 3 个哨兵,那么还是可以拿到半数以上(5/2+1=3)的票、且也达到了 quorum 值,满足了选举 Leader 的两个条件,所以就能选举成功,因此哨兵集群可以完成主从切换

​ 如果 5 个哨兵,quorum 设置为 2,3 个哨兵故障 =》 有机会判定主节点"客观下线",但无法完成主从切换

​ 如果 5 个哨兵,quorum 设置为 3,3 个哨兵故障 =》 无法判定主节点"客观下线",也无法完成主从切换

一般建议quorum 设置为哨兵个数的二分之一加1

(2)主从故障转移过程分析

​ 在哨兵集群中通过投票的方式,选举出了哨兵 leader 后,就可以进行主从故障转移的过程

image-20240720121050170

主从故障转移步骤

  • 【步骤1】:在已下线主节点(旧主节点)属下的所有「从节点」里面,挑选出一个从节点,并将其转换为主节点;
  • 【步骤2】:让已下线主节点属下的所有「从节点」修改复制目标,修改为复制「新主节点」;
  • 【步骤3】:将新主节点的 IP 地址和信息,通过「发布者/订阅者机制」通知给客户端;
  • 【步骤4】:继续监视旧主节点,当这个旧主节点重新上线时,将它设置为新主节点的从节点;
【步骤1】:选出新主节点

​ 故障转移操作第一步要做的就是在已下线主节点属下的所有候选「从节点」中,按照指定规则挑选出一个状态良好、数据完整的从节点,然后向这个「从节点」发送 SLAVEOF no one 命令,解除其从节点的身份,并将这个「从节点」转换为「主节点」。

image-20240722082501139

​ 如果采取随机的方式,虽然实现起来很简单,但是如果选到一个网络状态不好的从节点作为新主节点,那么可能在将来不久又要做一次主从故障迁移。所以,首先要把网络状态不好的从节点给过滤掉,即将已经下线的从节点和以往网络连接状态不好的从节点过滤掉

怎么判断从节点之前的网络连接状态不好呢?

​ Redis 有个叫 down-after-milliseconds * 10 配置项,其 down-after-milliseconds 是主从节点断连的最大连接超时时间。如果在 down-after-milliseconds 毫秒内,主从节点都没有通过网络联系上,就可以认为主从节点断连了。如果发生断连的次数超过了 10 次,就说明这个从节点的网络状况不好,不适合作为新主节点。

过滤掉网络状态不好的从节点,随后进行三轮考察

​ 将网络状态不好的从节点过滤掉,随后要对所有从节点进行三轮考察:优先级、复制进度、ID 号。在进行每一轮考察的时候,哪个从节点优先胜出,就选其作为新主节点。

  • 第一轮考察:哨兵首先会根据从节点的优先级来进行排序,优先级越小排名越靠前;
  • 第二轮考察:如果优先级相同,则查看复制的下标,哪个从「主节点」接收的复制数据多,哪个就靠前;
  • 第三轮考察:如果优先级和下标都相同,就选择从节点 ID 较小的那个;

第一轮考察:优先级最高的从节点胜出

​ Redis 中通过 slave-priority 配置项给从节点设置优先级。每一台从节点的服务器配置不一定是相同的,可以根据服务器性能配置来设置从节点的优先级。

​ 比如,如果「A 从节点」的物理内存是所有从节点中最大的,则可以把「A 从节点」的优先级设置成最高。这样当哨兵进行第一轮考虑的时候,优先级最高的 A 从节点就会优先胜出,于是就会成为新主节点

第二轮考察:复制进度最靠前的从节点胜出

​ 如果在第一轮考察中,发现优先级最高的从节点有两个,则会进行第二轮考察,比较两个从节点的复制进度。

复制进度:主从架构中,主节点会将写操作同步给从节点,在这个过程中,主节点会用 master_repl_offset 记录当前的最新写操作在 repl_backlog_buffer 中的位置(如下图中的「主服务器已经写入的数据」的位置),而从节点会用 slave_repl_offset 这个值记录当前的复制进度(如下图中的「从服务器要读的位置」的位置)。

​ 如果某个从节点的 slave_repl_offset 最接近 master_repl_offset,说明它的复制进度是最靠前的,于是就可以将它选为新主节点

image-20240722081425223

第三轮考察:ID 号小的从节点胜出

​ 如果在第二轮考察中,发现有两个从节点优先级和复制进度都是一样的,则进入第三轮考察,比较两个从节点的 ID 号,ID 号小的从节点胜出。

ID 号:每个从节点都有一个编号,这个编号就是 ID 号,是用来唯一标识从节点的

image-20240722085031792

【步骤2】:更新主从关系(将从节点指向新节点)

​ 当新主节点出现之后,哨兵 leader 下一步要做的就是,让已下线主节点属下的所有「从节点」指向「新主节点」,可通过向「从节点」发送 SLAVEOF 命令来实现新的主从关系绑定

​ 如下图,哨兵 leader 向所有从节点(server3 和 server4)发送 SLAVEOF指令 ,让它们成为新主节点的从节点。

image-20240722085718356

【步骤3】:通知客户端主节点已更换

​ 基于上述步骤,哨兵集群完成主从切换的工作,随后需将新的主节点信息通知给客户端。这一步骤是通过Redis的发布者/订阅者机制来实现的,每个哨兵节点提供发布者/订阅者机制,客户端可以从哨兵订阅消息。哨兵提供的消息订阅频道有很多,不同频道包含了主从节点切换过程中的不同关键事件,常见事件参考如下:

事件相关频道
主库下线事件+sdown(实例进入【主观下线】状态)
-sdown(实例退出【主观下线】状态)
+odown(实例进入【客观下线】状态)
-odown(实例退出【客观下线】状态)
从库重新配置事件+slave-reconf-sent(哨兵发送slaveof命令重新配置从库)
+slave-reconf-inprog(从库配置了新主库,但未进行同步)
+slave-reconf-done(从库配置了新主库,且和新主库完成同步)
新主库切换+switch-master(主库地址发生变化)

​ 客户端和哨兵建立连接后,客户端会订阅哨兵提供的频道。主从切换完成后,哨兵就会向 +switch-master 频道发布新主节点的 IP 地址和端口的消息,这个时候客户端就可以收到这条信息,然后用这里面的新主节点的 IP 地址和端口进行通信

​ 通过发布者/订阅者机制机制的事件通知,客户端不仅可以在主从切换后得到新主节点的连接信息,还可以监控到主从节点切换过程中发生的各个重要事件,以此主从切换进行到哪一步了,有助于了解切换进度

【步骤4】:监视旧主节点并将其变为从节点

​ 故障转移操作的收尾工作就是继续监视旧主节点并更新主从关系,当旧主节点重新上线时,哨兵集群就会向它发送 SLAVEOF 命令,让它成为新主节点的从节点。至此,完成整个主从节点的故障转移工作

image-20240722085703009

3.哨兵集群

​ 哨兵集群的搭建配置参考如下:

# 设置主节点名字、主节点的 IP 地址和端口号以及 quorum 值
sentinel monitor <master-name> <ip> <redis-port> <quorum> 

​ 基于上述配置会发现,只配置了主节点的关键信息,而不需要填充其他哨兵节点的信息,此处可能会思考一个问题,这些节点是如何感知对方?又是如何组成哨兵集群的?

哨兵集群如何构建?这些节点如何感知对方?

哨兵节点是通过Redis 的发布者/订阅者机制来相互发现的

​ 在主从集群中,主节点上有一个名为__sentinel__:hello的频道,不同哨兵就是通过它来相互发现,实现互相通信的。

​ 在下图中,哨兵 A 把自己的 IP 地址和端口的信息发布到__sentinel__:hello 频道上,哨兵 B 和 C 订阅了该频道。那么此时,哨兵 B 和 C 就可以从这个频道直接获取哨兵 A 的 IP 地址和端口号。基于此,哨兵 B、C 可以和哨兵 A 建立网络连接,哨兵B和C也可以建立网络连接,进而形成哨兵集群

image-20240722092113131

哨兵集群会对「从节点」的运行状态进行监控,那哨兵集群如何知道从节点的信息?

​ 主节点知道所有「从节点」的信息,所以哨兵会每 10 秒一次的频率向主节点发送 INFO 命令来获取所有「从节点」的信息。

​ 如下图所示,哨兵 B 给主节点发送 INFO 命令,主节点接受到这个命令后,就会把从节点列表返回给哨兵。接着,哨兵就可以根据从节点列表中的连接信息,和每个从节点建立连接,并在这个连接上持续地对从节点进行监控。哨兵 A 和 C 可以通过相同的方法和从节点建立连接

image-20240722092739049

通过 Redis 的发布者/订阅者机制,哨兵之间可以相互感知,构建哨兵集群。与此同时,哨兵通过 INFO 命令,在主节点里获得了所有从节点连接信息,就能和从节点建立连接,并进行监控

4.哨兵机制核心总结

​ Redis 在 2.8 版本以后提供的哨兵(Sentinel)机制,它的作用是实现主从节点故障转移。它会监测主节点是否存活,如果发现主节点挂了,它就会选举一个从节点切换为主节点,并且把新主节点的相关信息通知给从节点和客户端。

​ 哨兵一般是以集群的方式部署(至少需要 3 个哨兵节点),哨兵集群工作核心:监控、选主、通知通过 Redis 的发布者/订阅者机制,哨兵之间可以相互感知,构建哨兵集群。与此同时,哨兵通过 INFO 命令,在主节点里获得了所有从节点连接信息,就能和从节点建立连接,并进行监控

两轮投票+故障转移

第一轮投票:判断主节点下线监控:主观下线、客观下线)

​ 当哨兵集群中的某个哨兵判定主节点下线(主观下线)后,就会向其他哨兵发起命令,其他哨兵收到这个命令后,就会根据自身和主节点的网络状况,做出赞成投票或者拒绝投票的响应。

​ 当这个哨兵的赞同票数达到哨兵配置文件中的 quorum 配置项设定的值后,这时主节点就会被该哨兵标记为「客观下线」。

第二轮投票:选出哨兵 leader(由该哨兵Leader进行主从故障转移)

​ 某个哨兵判定主节点客观下线后,该哨兵就会发起投票,告诉其他哨兵,它想成为 leader,想成为 leader 的哨兵节点,要满足两个条件:

  • 条件1:拿到半数以上的赞成票;
  • 条件2:拿到的票数需大于等于哨兵配置文件中的 quorum 值;

故障转移:由哨兵 leader 进行主从故障转移选主、通知

​ 选举出了哨兵 leader 后,就可以进行主从故障转移的过程了。该操作包含以下四个步骤:

  • 【步骤1】:选主 => 在已下线主节点(旧主节点)属下的所有「从节点」里面,挑选出一个从节点,并将其转换为主节点,选择的规则:
    • 过滤掉已经离线、历史网络连接状态不好的从节点;
    • 进行三轮考察筛选:优先级、复制进度、ID 号。在每一轮考察过程中,如果找到了一个胜出的从节点,就将其作为新主节点
  • 【步骤2】:更新主从关系:让已下线主节点属下的所有「从节点」修改复制目标,修改为复制「新主节点」;
  • 【步骤3】:通知 => 将新主节点的 IP 地址和信息,通过「发布者/订阅者机制」通知给客户端;
  • 【步骤4】:继续监视旧主节点,当这个旧主节点重新上线时,将它设置为新主节点的从节点;
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.1.3