Redis Sentinel架构
复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的,但它故障恢复无法自动化,因此Redis提供了哨兵(Sentinel)这么一个高可用方案。Redis Sentinel由两部分组成,哨兵节点和数据节点:
- 哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的redis节点,不存储数据。
- 数据节点:主节点和从节点都是数据节点。
Redis Sentinel具有以下功能:
- 监控:哨兵通过心跳检测会不断地检查主节点和从节点是否运作正常。
- 自动故障转移:当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。
- 配置提供者:客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。
- 通知:哨兵可以将故障转移的结果发送给客户端。
客户端连接Redis Sentinel
对于Redis Sentinel,它仅仅完成了服务端的高可用,当master挂掉时能选举出一个新的master节点来完成故障转移,但是我们客户端并没有去连接新的master节点,因此我们还要使得客户端也是高可用的。
Jedis客户端对Redis Sentinel提供了很好的支持。我们只需要向Jedis提供sentinel节点集合和masterName
,构造JedisSentinelPool
对象,然后便可以像使用普通redis连接池一样来使用了:通过pool.getResource()
获取连接,执行具体的命令。
1 | public static void testSentinel() throws Exception { |
在整个过程中,我们的代码不需要显式的指定主节点的地址,就可以连接到主节点。代码中对故障转移也没有任何体现,就可以在sentinel完成故障转移后自动的切换主节点。之所以可以做到这些,是因为客户端完成了以下几个工作:
- 遍历sentinel节点,找到一个可用的sentinel节点,通过
sentinel get-master-addr-by-name
命令获取master节点的信息(IP和端口),之后再对master节点执行role
命令判断其是否真的为master节点。 - 客户端和sentinel使用了一个发布订阅模式,客户端订阅sentinel的某一个频道,当master发生变化时,sentinel向这个频道发布一条消息,客户端就可以获取再对新的master进行一个连接。
前面说过sentinel相当于配置提供者,我们得到了sentinel的集合后就可以通过sentinel节点获取到master的地址。这里要注意sentinel只是配置提供者,而不是代理,二者的区别在于如果是配置提供者,客户端在通过sentinel获得master信息后,会直接建立到master的连接,后续的请求会直接发向master,而如果是代理,客户端的每一次请求都会发向sentinel,sentinel再通过主节点处理请求。
基本原理
三个定时任务
- 10秒每个sentinel对master和slave执行info,以此发现slave节点并确认主从关系。
- 2秒每个sentinel通过master节点的channel交换信息(因此sentinel节点之间能够自动感知)。
- 每1秒每个sentinel对其它sentinel和redis执行ping也就是心跳检测。
主观下线和客观下线
- 主观下线:在心跳检测的定时任务中,如果其他节点超过一定时间没有回复,哨兵节点就会将其进行主观下线。顾名思义,主观下线的意思是一个哨兵节点“主观地”判断下线。
- 客观下线:哨兵节点在对主节点进行主观下线后,会通过
sentinel is-master-down-by-addr
命令询问其他哨兵节点该主节点的状态。如果判断主节点下线的哨兵数量达到设置的法定人数(quorum),则对该主节点进行客观下线。
需要特别注意的是,客观下线是主节点才有的概念,如果从节点和哨兵节点发生故障,被哨兵主观下线后,不会再有后续的客观下线和故障转移操作。
领导者选举
由于只需要一个sentinel节点完成故障转移,因此sentinel内部需要选举出一个节点作为领导者,同样也是通过sentinel is-master-down-by-addr
这个命令完成领导者的选举(这正是这条命令的第二个作用)。过程如下:
- 每个做主观下线的sentinel节点向其它sentinel节点发送命令,要求将它设置为领导者。
- 收到命令的sentinel节点如果没有同意通过其它sentinel节点发送的命令,那么将同意该请求,否则拒绝。
- 如果该sentinel节点发现自己的票数已经超过sentinel集合半数并且超过quorum,那么将它成为领导者。
故障转移
完成了领导者选举后,由领导者进行故障转移操作:
- 从slave节点中选出一个“合适的”节点作为新的master节点:选择优先级最高的从节点(由
slave-priority
指定);如果优先级无法区分,则选择复制偏移量最大的从节点;如果仍无法区分,则选择runid最小的从节点。 - 对上面slave节点执行
slaveof no one
命令让其成为master节点。 - 向剩余的slave节点发送命令,让它们成为新master节点的slave节点,复制规则和
parallel-syncs
参数有关。 - 更新原来master节点配置为slave,并保持着对其“关注”,当其恢复后命令它去复制新的master节点。
常见问题
Redis Sentinel无法对从节点进行自动故障转移,在读写分离场景下,从节点故障会导致读服务不可用,需要我们对从节点做额外的监控、切换操作。除此之外,它的存储能力受到单机限制的问题,因此如果我们对扩容有需求的话,应当使用Redis Cluster这么一个高可用的集群方案。
参考资料
- 《Redis开发与运维》
- 深入学习Redis(4):哨兵