Redis 哨兵集群
哨兵集群
哨兵机制是在 redis 2.8 引入的,核心功能就是当主库发生故障自动故障转移,它本质其实就是一个 redis 进程,下图就是一个基本的哨兵集群。
故障转移的基本流程是, 监控-选主-通知
哨兵在运行的时候,会周期性(一秒)的给所有的节点发送 PING 命令来检测节点是否处于正常状态。如果节点没有在配置时间内响应那么就会被标示为下线状态。如果是主库被下线,哨兵会按照一定的规则在从库中选取一个节点作为新的主库完成切换,完成新的主库切换后哨兵会把新的主库信息发送从库。让从库和新的主库建立连接后进行数据复制。
哨兵集群实例之间会有互相发现的功能。依赖于 redis 提供的发布/订阅机制。
哨兵在和主库建立连接后会在主库/从库的 __sentinel__:hello
频道每隔两秒发布自己的信息其中就包含了 IP、端口、ID,除此之外还会发布自己监控主库的完整配置,如果自身配置比其他哨兵发布的的要旧,它会立即更新为新配置。
也会订阅该频道实现哨兵集群的互相通信,当哨兵发现一个新的哨兵节点时会把新的哨兵节点信息添加到一个列表中,这个列表保存着当前哨兵已知监视同一个主库的其他哨兵信息。
同时哨兵每隔10秒会向自己监控的主库发送 info
命令来获取从库列表,从而和每个从库建立连接。(如果主库被客观下线,频率会变成1秒一次)
哨兵本身也会有发布订阅机制的。客户端可以通过订阅哨兵的频道获取主控切换过程中不同的时间。主要频道如下
<instance details>
表示 <instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>
@
后面是主库信息,是可选的,@ 前面是指定的节点。 譬如 +sdown master mymaster 127.0.0.1 6379
和 +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381
+sdown <instance details>
节点处于主观下线状态-sdown <instance details>
节点退出主观下线状态+odown <instance details>
节点进处于客观下线状态-sdown <instance details>
节点退出客观下线状态+slave-reconf-sent <instance details>
哨兵发送 replicaof 命令重新配置从库所属的主库+slave-reconf-inprog <instance details>
从库将自己设置为新主库的从库,但是还未和新主库进行数据同步+slave-reconf-done <instance details>
从库与新新主库完成了数据同步+switch-master <master name> <oldip> <oldport> <newip> <newport>
主库地址发生了变化
下线状态
当节点的出现故障时会被标记为下线状态,下线状态有两个类型。
- 主观下线(Subjectively Down) 简称 SDOWN ,是单哨兵对节点做出的下线判断。
- 客观下线(Objectively Down) 简称 ODOWN ,是多个哨兵对同一个主节点做出的判断。通常客观下线的标准是当有 N 个哨兵时,需要有 N/2+1 个实例判断为主观下线后才能被标示为客观下线。
注:客观下线只适用于主节点,从节点永远不会进入客观下线状态,当哨兵标示从节点为主观下线后就会直接下线这个节点。
当哨兵对主节点判断为主观下线后,它会给其他哨兵发送一条 is-master-down-by-addr
命令。其他哨兵需要根据自身的判断响应 Y/N
。当得到所需的赞成票会标示住节点为客观下线状态。 quorum
配置该项,假如当哨兵集群数量为 3,quorum
配置 2 ,就需要包括自己一共2票才能标示为客观下线。
选主
当主库下线后哨兵需要从一众从库中选取一个作为新的主库。大致的过程的是先按照一定的筛选条件,筛选出符合条件的从库,然后在按照一定的规则给符合条件的从库进行评估是否可以作为合适的主库。
筛选条件主要是从库的当前在线状态,和从库之前的网络链接状态如果一个从库之前一直和主库有闪断,而且次数达到了一定的阈值,那么这个从库网络状态就不稳定,不适合作为主库。
配置项 down-after-milliseconds * 5
前者表示主从断连的最大超时时间,后者是断链次数,如果超过五次那么这个从库就被认为是不可靠的。需要注意所有哨兵实例的 down-after-milliseconds
配置必须保持一致。否则哨兵集群在对主库下线判断会存在不一致的情况。
评估一般是三步。
- 通过配置的从库优先级,通过
replica-priority
可以给不同的从库配置优先级,譬如可以给配置高的从库设置较高的优先级。replica-priority
,值越小表示优先级越高,譬如哨兵1的优先级是10,哨兵2的是100,那么哨兵1的优先级高于哨兵2。设置为 0,示该从节点不参与主节点的竞选。 - 判断从库和下线主库同步程度,同步程度最高的从优先级最高。通过判断从库
slave_repl_offset
的值和master_repl_offset
值的差值,越接近就说明同步 - 如果多个从库有相同的优先级和数据同步程度,选择ID最小的从库作为新主库。ID较小的从库并没有任何优势,只是有助于主库选择过程中更加具有确定性
大致过程:
哨兵选举
当新的主库被选定后,哨兵就需要进行主从切换的操作,但是具体是哪个哨兵来执行还需要进行投票选出一个 leader 哨兵。哨兵选举采用的 Raft 算法。Raft 算法可以保证在给定的一个任期内最多只有一个领导人,详细的 Raft 算法可以看这里。
大致流程是当哨兵认定主库为客观下线状态后,会向其他哨兵发送命令希望自己成为 leader。成为 leader 需要满足两条,第一是拿到半数以上的赞成票,第二是票数同时要大于等于 quorum
, 假如哨兵数量为 3 ,quorum
配置为2,大致流程如下:
如果当轮选举没有任何一个哨兵获得半数票,那么哨兵集群会等待一段时间(2 * failover-timeout)后重新选举,因为哨兵集群进行投票很依赖网络传播,如果网络阻塞就可能会出现没有个哨兵获得半数票的情况。
quorum
配置可以有效的控制哨兵集群对主库故障的铭感度:
- 如果值相对小于大多数哨兵,那么哨兵对主库的故障检测就会很铭感。譬如有5个哨兵,
quorum
配置为2,那么只要2个哨兵认定主库主观下线主库就会被客户端下线,但是 leader 哨兵需要3个哨兵的赞成票才能进行主从切换。 - 如果值相大于大多数哨兵,那么哨兵对主库检测就会很迟钝,譬如配置成5,那么就需要5个哨兵全部达成一致才行。
最后
当 leader 哨兵准备开始进行主从切换时就会发布新主库的信息,方便其他哨兵更新主库信息。之后 leader 哨兵向指定从库发送 REPLICAOF NO ONE
命令后,通过 INFO
来观察是否去切换到主库,至此主从切换就算成功了。
所有的哨兵会开始往 _sentinel__:hello
频道发布新的主库配置和自身的信息。同时所有哨兵也会查看其他哨兵发布的配置的什么以便更新自己的配置。这里有一个问题就是怎么区分最新的配置,简单来说哨兵在发布配置的时候会带有一个版本号,譬如之前在未进行主从切换时配置版本是1。完成切换后是2,这样所有的哨兵都会看到此配置并且更新自己的配置。