Redis Sentinel哨兵机制
[toc]
什么是redis sentinel
哨兵在redis集群架构中是一个非常重要的组件,其主要功能有下面这些:
- 集群监控,即时刻监控着redis的master和slave进程是否是在正常工作。
- 消息通知,就是说当它发现有redis实例有故障的话,就会发送消息给管理员
- 故障自动转移,如果redis master 节点宕机了的话,它就会将请求转到slave 节点上,slave升为master。
- 充当配置中心,如果发生了故障转移,它会通知将master的新地址写在配置中心告诉客户端。
sentinel 本身也是分布式部署的,是一个集群去运行的并且节点间相互协调工作,那它是怎么来监控redis的呢?
- 当发生故障转移的时候,只有大部分哨兵节点同意(选主)才会判断你这个master是真的宕机
- 如果哨兵部分节点挂了的话,整个哨兵集群依然能工作,这也是确保自身能高可用
哨兵集群至少要 3 个节点,来确保自己的健壮性;redis主从 + sentinel的架构,是不会保证数据的零丢失的,它是为了保证redis集群的高可用。
三个监控任务
哨兵节点通过三个定时监控任务监控 Redis 数据节点的服务可用性。
①info 命令
每隔 10 秒,每个哨兵节点都会向主、从 Redis 数据节点发送 info 命令,获取新的拓扑结构信息。Redis 拓扑结构信息包括了:
本节点角色:主或从
主从节点的地址、端口信息
这样,哨兵节点就能从 info 命令中自动获取到从节点信息,因此那些后续才加入的从节点信息不需要显式配置就能自动感知。
②向 __sentinel__:hello 频道同步信息
通过redis的pub/sub,每隔 2 秒,每个哨兵节点将会向 Redis 数据节点的__sentinel__:hello 这个channel里同步自身得到的主节点信息以及当前哨兵节点的信息。
由于其他哨兵节点也订阅了这个channel,因此实际上这个操作可以交换哨兵节点之间关于主节点以及哨兵节点的信息。

这一操作实际上完成了两件事情:
发现新的哨兵节点:如果有新的哨兵节点加入,此时保存下来这个新哨兵节点的信息,后续与该哨兵节点建立连接。
交换主节点的状态信息,作为后续客观判断主节点下线的依据。
③向数据节点做心跳探测

每隔 1 秒,每个哨兵节点向主、从数据节点以及其他 Sentinel 节点发送 Ping 命令做心跳探测,这个心跳探测是后续主观判断数据节点下线的依据。
主观下线和客观下线
主观下线
上面三个监控任务中的第三个探测心跳任务,如果在配置的 down-after-milliseconds 之后没有收到有效回复,那么就认为该数据节点“主观下线(sdown)”。

为什么称为“主观下线”?因为在一个分布式系统中,有多个机器在一起联动工作,网络可能出现各种状况,仅凭一个节点的判断还不足以认为一个数据节点下线了,这就需要后面的“客观下线”。
客观下线

当一个哨兵节点认为主节点主观下线时,该哨兵节点需要通过”sentinel is-master-down-by addr”命令向其他哨兵节点咨询该主节点是否下线了,如果有超过半数的哨兵节点都回答了下线,此时认为主节点“客观下线”。
切主流程
选举哨兵领导者
当主节点客观下线时,需要选举出一个哨兵节点做为哨兵领导者,以完成后续选出新的主节点的工作。
这个选举的大体思路是:
- 每个哨兵节点通过向其他哨兵节点发送”sentinel is-master-down-by addr”命令来申请成为哨兵领导者。
- 而每个哨兵节点在收到一个”sentinel is-master-down-by addr”命令时,只允许给第一个节点投票,其他节点的该命令都会被拒绝。
- 如果一个哨兵节点收到了半数以上的同意票,则成为哨兵领导者。
- 如果前面三步在一定时间内都没有选出一个哨兵领导者,将重新开始下一次选举。
可以看到,这个选举领导者的流程很像 Raft 中选举 Leader 的流程。
选出新的主节点

在剩下的 Redis 从节点中,按照以下顺序来选择新的主节点:
- 过滤掉“不健康”的数据节点:比如主观下线、断线的从节点、五秒内没有回复过哨兵节点 Ping 命令的节点、与主节点失联的从节点。
- 选择 Slave-Priority(从节点优先级)最高的从节点,如果存在则返回,不存在则继续后面的流程。
- 选择复制偏移量最大的从节点,这意味着这个从节点上面的数据最完整,如果存在则返回,不存在则继续后面的流程。
- 到了这里,所有剩余从节点的状态都是一样的,选择 runid 最小的从节点。
提升新的主节点

选择了新的主节点之后,还需要最后的流程让该节点成为新的主节点:
- 哨兵领导者向上一步选出的从节点发出“slaveof no one”命令,让该节点成为主节点。
- 哨兵领导者向剩余的从节点发送命令,让它们成为新主节点的从节点。
- 哨兵节点集合会将原来的主节点更新为从节点,当其恢复之后命令它去复制新的主节点的数据。
主备切换中的数据丢失问题
1. 主从异步复制导致的数据丢失
redis master 和slave 数据复制是异步的,和的MySQL差不多,这样就有可能会出现部分数据还没有复制到slave中,master就挂掉了,那么这部分的数据就会丢失了。

2. 脑裂导致的数据丢失
脑裂其实就是网络分区导致的现象,比如,master机器网络突然不正常了发生了网络分区,和其他的slave机器不能正常通信了,其实master并没有挂,但是哨兵会认为master挂掉了,client可能还在继续写master,还没来得及更新到新的master,那这部分数据就会丢失。
上面的两个数据丢失的问题,那该怎么去解决呢?其实也很简单,只需要在配置中加两个配置就行了,如下:
1 | min-slaves-to-write 1 # 要求至少一个slave |
来分析下,加上了这两个配置是怎么解决数据丢失问题的。核心思想就是:一旦所有的slave节点,在数据复制和同步时延迟了超过10秒的话,那么master它就不会再接客户端的请求了,这样就会有效减少大量数据丢失的发生。
如何减少异步复制数据的丢失
当slave在数据复制的时候,发现返回的ACK时延太长达到了 min-slaves-max-lag 配置,这个时候就会认为如果master宕机就会导致大量数据丢失,所以就提前进行了预测,就不再去接收客户端的任何请求了,来将丢失的数据降低在可控范围内。
减少脑裂数据的丢失
- 如果master出现了脑裂,和其他的slave失去了通信,不能继续给指定数量的slave发送数据。
- slave超过10秒没有给自己返回ack消息。
- master就会拒绝客户端的写请求
转载自:
https://zhuanlan.zhihu.com/p/95678924
https://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=2655824267&idx=1&sn=dfe90cb364d884a6197a1621cf553786&chksm=bd74e45c8a036d4abc741237c65c80ca5a0f3bd976e6c5ebe077dc2e517fccba4d07b8a0b7bf&xtrack=1&scene=90&subscene=93&sessionid=1557915135&clicktime=1557915141&ascene=56&devicetype=android-27&version=2700043a&nettype=WIFI&abtest_cookie=BAABAAoACwASABMABQAjlx4AyZkeANyZHgD1mR4AAJoeAAAA&lang=zh_CN&pass_ticket=ej3eAEgovFuxG01K43k1aKaxiH6Ze9CZOQaEU9Fz4zUyLRvpG06zHSJ%2FBG9uj0K8&wx_header=1