当主从切换发生时,一定是有超过预设数量(quorum 配置项)的哨兵实例和主库的心跳都超时了,才会把主库判断为客观下线,然后,哨兵开始执行切换操作。哨兵切换完成后,客户端会和新主库进行通信,发送请求操作。
但是,在切换过程中,既然客户端仍然和原主库通信,这就表明,原主库并没有真的发生故障(例如主库进程挂掉)。
主从切换后,从库一旦升级为新主库,哨兵就会让原主库执行 slave of 命令,和新主库重新进行全量同步。而在全量同步执行的最后阶段,原主库需要清空本地的数据,加载新主库发送的 RDB 文件,这样一来,原主库在主从切换期间保存的新写数据就丢失了
Redis 已经提供了两个配置项来限制主库的请求处理,分别是 min-slaves-to-write 和 min-slaves-max-lag。
min-slaves-to-write:这个配置项设置了主库能进行数据同步的最少从库数量; min-slaves-max-lag:这个配置项设置了主从库间进行数据复制时,从库给主库发送 ACK 消息的最大延迟(以秒为单位)。 我们可以把 min-slaves-to-write 和 min-slaves-max-lag 这两个配置项搭配起来使用,分别给它们设置一定的阈值,假设为 N 和 T。这两个配置项组合后的要求是,主库连接的从库中至少有 N 个从库,和主库进行数据复制时的 ACK 消息延迟不能超过 T 秒,否则,主库就不会再接收客户端的请求了。
即使原主库是假故障,它在假故障期间也无法响应哨兵心跳,也不能和从库进行同步,自然也就无法和从库进行 ACK 确认了。这样一来,min-slaves-to-write 和 min-slaves-max-lag 的组合要求就无法得到满足,原主库就会被限制接收客户端请求,客户端也就不能在原主库中写入新数据了。
多个 sentinel 会选出一个 leader,具体的选举机制是依据 Raft 分布式一致性协议。
通过上面的配置文件可以发现,只配置了 Redis master 的地址,并没有配置 slave 和其他 sentinel 的地址。
那是怎么知道的呢?
发现 slave 比较简单,通过询问 master 就可以得到 slave 的地址。
发现其他 sentinel 是通过“发布/订阅”机制实现的。
每个 sentinel 都会向 __sentinel__:hello
这个频道发送消息,每秒一次,报告自己的存在。
每个 sentinel 也会订阅这个频道,就可以发现其他的 sentinel 了。
Sentinel
集群选举Leader
Sentinel Leader
决定新主节点Sentinel集群的每一个Sentinel节点会定时对redis集群的所有节点发心跳包检测节点是否正常。如果一个节点在down-after-milliseconds
时间内没有回复Sentinel节点的心跳包,则该redis节点被该Sentinel节点主观下线。
当节点被一个Sentinel节点记为主观下线时,并不意味着该节点肯定故障了,还需要Sentinel集群的其他Sentinel节点共同判断为主观下线才行。
该Sentinel节点会询问其他Sentinel节点,如果Sentinel集群中超过quorum
数量的Sentinel节点认为该redis
节点主观下线,则该redis
客观下线。
如果客观下线的redis
节点是从节点或者是Sentinel节点,则操作到此为止,没有后续的操作了;如果客观下线的redis
节点为主节点,则开始故障转移,从从节点中选举一个节点升级为主节点。
Leader
如果需要从redis集群选举一个节点为主节点,首先需要从Sentinel
集群中选举一个Sentinel
节点作为Leader
。
每一个Sentinel
节点都可以成为Leader
,当一个Sentinel
节点确认redis集群的主节点主观下线后,会请求其他Sentinel
节点要求将自己选举为Leader
。被请求的Sentinel
节点如果没有同意过其他Sentinel
节点的选举请求,则同意该请求(选举票数+1),否则不同意。
如果一个Sentinel
节点获得的选举票数达到Leader
最低票数(quorum
和Sentinel节点数/2+1
的最大值),则该Sentinel
节点选举为Leader
;否则重新进行选举。
Sentinel Leader
决定新主节点当Sentinel
集群选举出Sentinel Leader
后,由Sentinel Leader
从redis从节点中选择一个redis节点作为主节点:
过滤故障的节点
选择优先级slave-priority
最大的从节点作为主节点,如不存在则继续
选择复制偏移量(数据写入量的字节,记录写了多少数据。主服务器会把偏移量同步给从服务器,当主从的偏移量一致,则数据是完全同步)最大的从节点作为主节点,如不存在则继续
选择runid
(redis每次启动的时候生成随机的runid
作为redis
的标识)最小的从节点作为主节点
为什么Sentinel
集群至少3节点
一个Sentinel
节选举成为Leader
的最低票数为quorum
和Sentinel节点数/2+1
的最大值,如果Sentinel
集群只有2个Sentinel
节点,则
Sentinel节点数/2 + 1= 2/2 + 1= 2
即Leader
最低票数至少为2,当该Sentinel
集群中由一个Sentinel
节点故障后,仅剩的一个Sentinel
节点是永远无法成为Leader
。
也可以由此公式可以推导出,Sentinel
集群允许1个Sentinel
节点故障则需要3个节点的集群;允许2个节点故障则需要5个节点集群。
https://blog.css8.cn/post/2305362.html
集群选举的处理 在 RedisCluster 集群实现原理 中提到过从节点通过选举晋升为主节点的过程,其处理大致如下:
Slave 节点在每个周期任务中都会检查 Master 节点是否 FAIL,如是则尝试进行 Failover,以期成为新的 Master。不过在此之前需要过滤可用的 Slave 节点,具体做法就是检查每个 Slave 节点与 Master 节点断开连接的时间,如果超过了cluster-node-timeout * cluster-slave-validity-factor,那这个Slave 节点就没有资格切换成 Master 由于挂掉的 Master 可能会有多个 Slave 节点,所以在 Slave 节点发起选举前需要根据所有 Slave 节点的复制偏移量确定一个选举的优先级,Slave 节点的优先级越小则其发起选举的时间越靠前 当 Slave 节点到达其选举时间时,将自身的 currentEpoch 变量(该变量可视作集群所处版本的记录)自增,然后向集群中所有的节点发送 CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST 消息,请求其他集群节点进行投票 所有集群节点都会收到广播消息,但是只有 Master 节点会对其进行回应。Master 节点首先确定自身 currentEpoch 变量 是否小于广播消息中请求投票的 Slave 节点的currentEpoch 变量 ,再加上其他一些校验最终确定是否为 Slave 节点投票。如果决定投票,则回复 CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK 消息 Slave 节点发出广播后,会定时检查其他节点返回的消息,并更新其计票器 server.cluster->failover_auth_count 当 Salve节点获得的票数超过了集群内 Master 节点总数的一半,则认为选举胜出,其自身将切换为 Master 节点,并广播主从切换完成的消息
事前,事中,事后三个层次去思考怎么来应对缓存雪崩的场景
https://www.cnblogs.com/sunliyuan/p/11594502.html
https://zhuanlan.zhihu.com/p/135864820