纸上得来终觉浅,绝知此事要躬行。
哨兵模式
Sentinel是Redis的高可用的解决方案,有多个Sentinel实例构成Sentinel系统。系统可以监视任意多个主服务器以及这些主服务器下的从服务器,当被监视的主服务器进入下线状态时,自动将下线的主服务属下的从服务器升级为新的主服务器,然后由新的主服务器替代下线主服务器继续处理命令请求。
下图展示了一个Sentinel系统监视服务器的例子:
假设此时,主服务器Master由于某种原因意外宕机下线,那么从服务器slave对主服务器的复制操作将被终止。并且Sentinel系统会察觉到Master已经下线。
当Master长时间处于下线,Sentinel系统将会对Master进行执行故障转移,之后Sentinel系统会在Master属下的从服务器挑选出一个作为新的主服务器,并且先其他slave发送复制指令,让他们从新的服务器开始复制。
当某个时间旧Master重新上线时,Sentinel系统会将它设置为新服务器的从服务器。
注意:以上的Sentinel系统中任意一台Sentinel都会监视所有的服务器
启动 Sentinel
- 对于 redis-sentinel 程序, 你可以用以下命令来启动 Sentinel 系统:
redis-sentinel /path/to/sentinel.conf
- 对于 redis-server 程序, 你可以用以下命令来启动一个运行在 Sentinel 模式下的 Redis 服务器:
redis-server /path/to/sentinel.conf --sentinel
配置Sentinel
配置项 | 示例 | 说明 |
---|---|---|
sentinel auth-pass <服务器名称> |
sentinel auth-pass mymaster ydongy |
连接服务器口令 |
sentinel down-after-milliseconds <自定义服务名称><主机地址><端口><主从服务器总量> |
sentinel monitor mymaster 1127.0.0.1 6379 1 |
设置哨兵监听的主服务器信息,最后的参数决定了最终参与选举的服务器数量 |
sentinel parallel-syncs <服务名称><服务器数(整数)> |
sentinel parallel-syncs mymaster 1 |
指定同时进行主从的slave数量,数值越大,要求网络资源越高,要求约小,同步时间约长 |
sentinel failover-timeout <服务名称><毫秒数(整数)> |
sentinel failover-timeout mymaster 9000 |
指定出现故障后,故障切换的最大超时时间,超过该值,认定切换失败,默认3分钟 |
sentinel notification-script <服务名称><脚本路径> |
服务器无法正常联通时,设定的执行脚本,通常调试使用。 |
工作原理
1. 建立与服务器之间的连接
Sentinel启动时会通过配置创建与指定主服务器的网络连接,Sentinel将成为主服务器的客户端,可以向主服务器发送命令,并且从命令的回复中获取相关服务器的信息。
对于每个被Sentinel监视和主服务器来说,Sentinel会创建两个异步网络连接:
- 命令连接:专门发送命令给主服务器
- 订阅连接:专门订阅主服务器的
__Sentinel__:hello
频道
Sentinel默认会每十秒发送一次info
命令,通过分析info
命令的回复获取主服务器当前信息以及根据当前主服务器下的从服务器ip
和port
地址信息,自动的发现从服务器。并保存在一个键为:ip:port
,值为从服务器的实例结构的字典当中。同样也会创建连接到从服务器的命令连接和订阅连接。整个结构如下图:
在创建命令之后,Sentinel在默认情况下,同样也会每十秒一次的频率通过命令连接向从服务器发送info
命令,获得从服务器的详细信息,根据这些信息,会对之前的从服务器实例结构进行更新。
2. 发送消息
在默认情况下,Sentinel会以每两秒一次的频率,通过命令连接向所有被监视的主服务器和从服务器发送命令到__Sentinel__:hello
频道:
PUBLISH __Sentinel__:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"
s_
表示Sentinel本身信息m_
表示主服务的信息
通过命令连接向__Sentinel__:hello
频道发送的消息,同时又会被订阅连接
从频道中获取出来,包括其他在__Sentinel__:hello
频道中的Sentinel同样也会接受到该信息(包括发送者自己)。举个例子,如下图:
由于每个Sentinel都会发送消息,也就是说任何一个Sentinel都会接受到自己以及其他Sentinel发送的消息,并且消息中含有Sentinel的信息,所以每个Sentinel都会把自己以及其他的Sentinel的信息保存在字典当中,键是ip:port
,值是一个Sentinel实例结构。当以后每次接受到消息,更新保存的信息,防止有宕机的Sentinel或者新添加的Sentinel。
3. 创建与其他Sentinel的命令连接
上一节说了在Sentinel向服务器通过命令连接发送信息,会被订阅连接接受到消息,如果发现一个字典当中不存在当前Sentinel,会为当前Sentinel创建相应的实例结构。
其实,同时会创建一个命令连接,而新Sentinel也会连接到这个Sentinel,相当于两两相连,如下图所示:
4. 主观下线
在默认情况下,Sentinel会一秒一次的频率向所有与它创建命令连接的服务器(包括:主服务器,从服务器,其他Sentinel)发送PING
命令,通过实例的返回恢复来判断实例时候在线。
发送PING
命令回复分为两种:
- 有效恢复:
+PONG
-LOADING
-MASTERDOWN
- 无效恢复:不包含以上三种,或者返回其他恢复
最开始启动Sentinel的时候,我们在配置文件中配置了一个down-after-milliseconds
的参数,如果在当前参数范围内没有一次有效恢复,那么当前Sentinel就认为该服务器主观下线,当然还可能存在多个Sentinel配置的时间大小不同,例如:
- Sentinel-1
sentinel monitor master 127.0.0.1 6379 2
sentinel down-after-milliseconds master 60000
- Sentinel-2
sentinel monitor master 127.0.0.1 6379 2
sentinel down-after-milliseconds master 20000
那么当master的断线时长超过20000毫秒之后,sentinel-2会判断该服务器主观下线,但是Sentinel-1认为master处于在线状态,之后当master断线60000毫秒之后,Sentinel-1和Sentinel-2才都会认为master进入主观下线状态。结合图查看一下:
5. 客观下线
当Sentinel将一个主服务器判断为主观下线之后,为了确保主服务器真正的下线,当前的Sentinel会先其他监视该服务器的Sentinel进行询问,看他们是否也认为主服务器进入下线状态,当Sentinel从其他Sentinel哪里接受到足够数量的以下线判断之后,Sentinel就会将服务判定为客观下线,之后便进行故障转移。
通过发送如下命令进行询问其他Sentinel:
SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <runid>
ip
:主服务器IP地址port
:主服务器端口号current_epoch
:Sentinel当前的配置纪元runid
:可以为*
表示仅仅检测主服务器的客观下线状态,或者是Sentinel的运行ID用于选举领头Sentinel
接受源Sentinel命令回复:
down_state
:返回接受者Sentinel的对主服务器的检查结果,1:下线,0:未下线leader_runid
:可以是*
表示仅仅检测主服务器的下线状态,或者接受者Sentinel的运行ID用于选举领头Sentinelleader_epoch
:接受者Sentinel的认为领头Sentinel的配置纪元
例如:
1
*
0
那么说明接受者Sentinel也同意主服务已下线。整个过程如图所示:
客观下线的判断条件是通过配置中sentinel monitor host6379 127.0.0.1 6379 2
最后一个参数决定,例如当前为2,意味着如果所有的Sentinel只要有两个认为主服务器下线,那么当前Sentinel才会将主服务判断为客观下线。
5. 选举领头Sentinel
在一个主服务器被判断为客观下线时,监视这个下线主服务器的一个Sentinel会进行协商,选出一个领头Sentinel去进行故障转移操作。
选取领头Sentinel规则和方法:
- 任意一个Sentinel都有可能
- 通过类似投票的方式,其实内部就是通过上面提到的回复
leader_epoch
,如果接受者Sentinel回复的参数是发送者Sentinel的运行ID,就表明当前Sentinel投给了发送者Sentinel这一票,只要有一个Sentinel的票数大于总票的一半以上,那么那个Sentinel就会成为领头Sentinel - 如果规定时间没有选出,那么在一段时间之后会再次进行选举,直到选出为止
6. 故障转移
在选举出领头Sentinel之后,领头Sentinel将对已下线的主服务器执行故障转移操作,包含以下步骤:
- 在主服务器属下的从服务器选择一个,转换为主服务器
- 让其他从服务器改为复制新的主服务器
- 将已经下线的服务器设置为新的主服务器的从服务器,一旦旧服务器上线之后,自动连接成为新服务器的从服务器
从服务器挑选规则:将所有从服务器保存到一个列表,对列表进行过滤:
- 删除列表中下线或断线的
- 最近5秒没有回复过领头Sentinel的
info
命令的 - 删除与主服务器断开连接过长的
- 根据从服务器优先级排序,选择优先级高的
- 优先级相同,按照复制的偏移量大小排序,选出偏移量最大的。偏移量大意味着保存的是最新的数据,
- 如果还存在多个,按照运行ID排序,选出运行ID最小的
选出之后发送命令sqlveof no one
,然后接着每秒一次发送info
命令,分析回复信息,直到被选中的从服务器的role
为master
,表示成功升级为主服务器。之后修改其他从服务器的复制目标,发送命令slaveof ip port
(ip是升级后的服务器ip,port是升级后服务器的port)。
当旧服务器重新上线,Sentinel会向它发送slaveof
命令,让他成* 为新的主服务器的从服务器。
Sentinel案例
sentinel-1 | sentinel-2 | sentinel-3 |
---|---|---|
port 26379 sentinel monitor host6379 127.0.0.1 6379 2 sentinel down-after-milliseconds host6379 60000 sentinel failover-timeout host6379 180000 sentinel parallel-syncs host6379 1 |
port 26380 sentinel monitor host6379 127.0.0.1 6379 2 sentinel down-after-milliseconds host6379 60000 sentinel failover-timeout host6379 180000 sentinel parallel-syncs host6379 1 |
port 26381 sentinel monitor host6379 127.0.0.1 6379 2 sentinel down-after-milliseconds host6379 60000 sentinel failover-timeout host6379 180000 sentinel parallel-syncs host6379 1 |
-
port
:配置哨兵端口 -
sentinel monitor host6379 127.0.0.1 6379 2
:指示 Sentinel 去监视一个名为 mymaster 的主服务器, 这个主服务器的 IP 地址为 127.0.0.1 , 端口号为 6379 , 而将这个主服务器判断为失效至少需要 2 个 Sentinel 同意 (只要同意 Sentinel 的数量不达标,自动故障迁移就不会执行)。 -
down-after-milliseconds
:选项指定了 Sentinel 认为服务器host6379已经断线所需的毫秒数。如果服务器在给定的毫秒数之内, 没有返回 Sentinel 发送的 PING 命令的回复, 或者返回一个错误, 那么 Sentinel 将这个服务器标记为主观下线。 只有在足够数量的 Sentinel 都将一个服务器标记为主观下线之后, 服务器才会被标记为客观下线,这时自动故障迁移才会执行。-
服务器对 PING 命令的有效回复可以是以下三种回复的其中一种:
- 返回 +PONG 。
- 返回 -LOADING 错误。
- 返回 -MASTERDOWN 错误。
如果服务器返回除以上三种回复之外的其他回复, 又或者在指定时间内没有回复 PING 命令, 那么 Sentinel 认为服务器返回的回复无效(non-valid)。
注意, 一个服务器必须在 master-down-after-milliseconds 毫秒内, 一直返回无效回复才会被 Sentinel 标记为主观下线。
举个例子, 如果 master-down-after-milliseconds 选项的值为 30000 毫秒(30 秒), 那么只要服务器能在每 29 秒之内返回至少一次有效回复, 这个服务器就仍然会被认为是处于正常状态的。
-
-
parallel-syncs
: 选项指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长。