本章内容
主要功能
Redis的主从架构中,当主服务器宕机,从服务器切换成主服务器的过程需要人工参与。 为此,Redis2.8版本后提供了哨兵工具来实现自动化的系统监控和故障恢复功能。
哨兵的主要作用是监控Redis系统的运行状况。主要功能:
- 监控(Monitoring):哨兵会不断地检查主节点和从节点是否运作正常。
- 自动故障转移(Automatic failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并将其他从节点更新为新主节点的从节点。
- 通知(Notification):哨兵通过pub/sub机制将故障转移的结果发送给客户端。
- 配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。
其中:
- 监控和自动故障转移功能,使得哨兵可以及时发现主节点故障并完成转移。
- 通知和配置提供者功能,使得客户端可以及时发现Redis集群的变更。
哨兵集群监控逻辑,如图所示:
核心原理
哨兵是一个运行在特殊模式下的Redis进程,与Redis主从实例一起运行,其核心功能主要有三项:监控、选主和通知。
监控
哨兵集群组建
哨兵搭建
组建一个由三个Redis节点192.168.31.106:6379(主节点)、192.168.31.106:6380(从节点-1)、192.168.31.106:6381(从节点-2)组成的Redis主从集群。
从Redis源码目录复制三份哨兵配置文件sentinel.conf,修改内容如下:
# sentinel实例端口
port 26379
# sentinel monitor <被监控主节点名称(此处可自定义)> <被监控主节点ip> <被监控主节点port> <quorum>
# quorum:只有超过quorum数量的哨兵认为主机已死,才能推举新的主机,quorum值最好超过Sentinel数量(单数)的一半
sentinel monitor master 192.168.31.106 6379 2
分别启动三个哨兵节点,执行命令:
redis-sentinel sentinel.conf
至此,由三个哨兵节点组成的哨兵架构搭建完成。
集群组建
哨兵搭建完成后,通过Redis提供的发布/订阅(pub/sub)机制实现哨兵实例之间的相互通信。
在主从集群中,Redis主库中有一个名为__sentinel__:hello的channel(频道),哨兵之间通过该频道进行交互,实现互相通信。如图所示:
图中,哨兵-1将自身的IP(192.168.31.106)和端口(26379)发布到Redis主库的频道(__sentinel__:hello)中,由于哨兵-2和哨兵-3订阅了该频道,因此哨兵-2和哨兵-3就可以从该频道中获取哨兵-1的IP和端口,这样哨兵-2、哨兵-3就顺利与哨兵1建立了网络连接。
以同样的方式,哨兵-2和哨兵-3也可以建立网络连接,至此,哨兵集群就形成了。之后哨兵集群通过该频道实现哨兵节点之间的信息交互(如:判定主库主观下线和客观下线)。
主从集群监控
哨兵集群组建完成后,哨兵通过向主节点发送INFO命令来获取主从集群中的从节点列表,根据返回的从节点列表中的连接信息与每个从节点建立连接,并基于该连接对从节点进行持续监控。如图所示:
下线判断
Redis主节点下线判断分为主观下线和客观下线。
主观下线(SDOWN):每个Sentinel会以每秒一次的频率向整个集群中的主节点、从节点以及其他Sentinel发送PING命令;如果一个实例(Instance)距离最后一次有效回复PING命令的时间超过参数down-after-milliseconds(默认值为30000,即:30s)设定的值, 则该实例会被Sentinel标记为主观下线。
客观下线(ODOWN):如果一个主节点被标记为主观下线,则正在监视该主节点的所有Sentinel会以每秒一次的频率确认该主节点是否真的进入主观下线状态;当有足够数量的Sentinel(大于等于配置文件中参数quorum设定的值)在指定时间范围内确认该主节点进入主观下线状态, 则标记该主节点为客观下线。
Sentinel询问其他Sentinel是否同意主节点已下线命令:sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid>。
发送命令:sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid>
ip:主观下线的服务ip
port:主观下线的服务端口
current_epoch:sentinel的纪元
runid:*表示检测服务下线状态,如果是sentinel的运行id,表示用来选举领头sentinel
其他Sentinel向源Sentinel返回一条包含三个参数的Multi Bulk信息作为sentinel is-master-down-by命令的回复:
回复内容主要包含三个参数:
down_state:1表示已下线,0表示未下线
leader_runid:领头sentinal runid
leader_epoch:领头sentinel纪元
如果源Sentinel发送的runid参数是*,则说明是确认主观下线,忽略leader_runid和leader_epoch参数;
如果源Sentinel发送的runid参数是源Sentinel的runid,则说明是Sentinel Leader选举,忽略down_state参数。
如图所示:
图中,哨兵-2判定主节点主观下线,向其他哨兵(哨兵-1、哨兵-3)发送is-master-down-by-addr命令,哨兵-1和哨兵-3根据自身与主节点的连接情况做出Y或N的响应(Y-下线,N-在线)。如果下线票数大于等于哨兵配置文件中的参数quorum设定的值(如:quorum=2),则判定主节点客观下线。
选主
选主指的是从Redis的所有从节点中选择一个从节点作为新的主节点。主要步骤包括哨兵选举、主节点选举、故障转移。
哨兵选举
判定Redis主节点客观下线后,需要从Redis集群的所有从节点中选择一个从节点作为Redis集群新的主节点。
具体由哨兵集群中的某个哨兵来完成Redis集群的主从切换,需要根据哨兵集群的选举机制产生。哨兵集群的选举机制是基于Raft算法。
选举流程:
- 1)判断客观下线的Sentinel节点分别向其他Sentinel节点发送自身的runId,请求将自己设置为Leader。
- 2)其他Sentinel节点收到请求后回复是否同意该节点成为Leader,根据先到先得原则,如果Sentinel节点已选择某个Sentinel节点(如:Sentinel-1)为Leader,则会拒绝其他Sentinel节点(即:Sentinel-2、Sentinel-3)的选举请求。
- 3)根据选举票数是否达到预定值(大于等于quorum和Sentinel节点数/2+1的最大值)来判定该节点是否成为Leader,达到预定值则选举完成,否则进入下一轮选举。
主节点选举
选举产生Sentinel Leader后,由Sentinel Leader从Redis集群的所有从节点中选举一个从节点作为新的主节点。
主节点选举流程:
- 1)筛选从节点,从所有从节点中过滤掉在线状态或网络连接状态(参数down-after-milliseconds)异常的从节点。
- 2)选择优先级slave-priority(配置项)最大的从节点作为主节点,如果slave-priority相同则继续比较从节点的复制偏移量。
- 3)选择复制偏移量最大的从节点作为主节点,如果复制偏移量相同则继续比较从节点的runId。
- 4)选择runId最小的从节点作为主节点。
故障转移
选举出Redis集群主节点后,需要根据已选举出来的主节点进行故障转移。
主要步骤:
- 1)被选举为主节点的从节点执行replicaof no one(Redis5.0以前为saveof no one) 命令脱离原主节点,使之升级为新的主节点。
- 2)其他从节点节点通过replicaof new master命令成为新主节点的从节点。
- 3)原主节点恢复后,将其设置为新主节点的从节点。
通知
哨兵节点在故障转移完成后,会将新的主节点信息发送给客户端,以便客户端及时切换主节点。
基于pub/sub机制的事件通知
哨兵是一个运行在特定模式下的Redis实例,它并不服务于请求操作,只是完成监控、选主和通知等任务。每个哨兵实例提供了pub/sub机制,客户端可以从哨兵实例中订阅消息。
哨兵提供了很多消息订阅频道(如:主库下线判断、新主库选定、从库重新配置等)。
客户端订阅频道
客户端通过读取哨兵的配置文件,获得哨兵的地址和端口与其建立网络连接,并在客户端执行订阅命令来获取不同的事件消息。如:
subscribe +switch-master
工作流程
哨兵机制的主要工作流程:
- 1)每个Sentinel以2秒/次的频率通过Master节点的频道(_sentinel_:hello)交换信息(如:组建哨兵集群、下线判断)。
- 2)每个Sentinel以10秒/次的频率向Master和Slave发送INFO命令,获取Redis集群的从节点列表并确定主从关系(监控Redis集群)。
- 3)每个Sentinel以1秒/次的频率向整个集群中的Master、Slave以及其他Sentinel发送一个PING命令(心跳检测)。
- 4)如果一个实例(Instance)距离最后一次有效回复PING命令的时间超过参数down-after-milliseconds设定的值, 则该实例会被Sentinel标记为主观下线。
- 5)当有足够数量的Sentinel(大于等于配置文件中参数quorum指定的值)确认Master进入了主观下线状态, 则Master会被标记为客观下线(注意:若没有足够数量的Sentinel确认Master客观下线, Master的客观下线状态就会被移除。若此时Master重新向Sentinel发送PING命令并得到有效回复,则Master的主观下线状态也会被移除)。
- 6)判定Master客观下线后,从Sentinel集群中选举一个Sentinel Leader节点来完成Redis集群的主从切换。
- 7)主从切换完成后,根据新选举出来的Master节点完成Redis集群故障转移。