这节介绍 Redis 的高可用解决方案:Sentinel
1. 介绍
Sentinel 是 Redis 官方推荐的高可用 (HA) 解决方案,当用 Redis 做 master-slave 的高可用方案时,假如 master 宕机了,Redis 本身 (包括它的很多客户端) 都没有实现自动进行主备切换。
Sentinel 本身是一个运行在特殊模式下的 Redis 服务器,它能监控多个 master-slave 集群,发现 master 宕机后能进行自动切换。
2. 获取信息方式
sentinel 通过配置项中的
sentinel monitor <master name> <master ip> <master port> <quorum>
选项来获取 master 节点的信息。
在启动后 sentinel 会建立同 master 节点的命令连接和订阅连接。以便通过命令连接向主节点发送命令,通过订阅连接订阅服务器的 _sentinel_:hello 频道。
sentinel 每 10 秒会向 master 节点发送 INFO 命令,通过分析命令的返回结果能够知道主节点和从节点的信息。对于每个从节点,sentinel 也会向它建立一个命令连接和订阅连接。
sentinel 每 2 秒通过命令连接向所监听的节点发送订阅命令,如
PUBLISH _sentinel_:hello …..
其中的信息包括了 sentinel 本身的信息以及自己记录的主节点信息。同时,sentinel 也会订阅_sentinel_:hello 频道,所以 sentinel 能够以这种方式同其他的 sentinel 节点通信,以同步信息, 见 goosip 协议。
当 sentinel 从订阅信息中发现一个新的 sentinel 节点时,会向该新发现的节点建立命令连接,最后监视同一主服务器的各个 sentinel 节点会形成互相连接的网络。
3. 节点失效
配置项
sentinel down-after-milliseconds < 主节点名 > < 中断时间 ms>
设置了 sentinel 主观下线的时间。sentinel 每隔一秒就会向主节点发送 PING 命令,如果 master 在“中断时间”内不回应 PONG 或者是回复了一个错误消息,那么这个 sentinel 会主观地 (单方面地) 认为这个 master 已经不可用了(SDOWN)。
当 sentinel 判断主节点已经处于主观下线状态后,会向其他 sentinel 发送
is-master-down-by-add
命令,以询问其他 sentinel 的状态,确认该主节点是否处于下线状态(主观下线或者客观下线)。当回复的下线状态的数量达到配置项中的 quorum 值时,则该 sentinel 会将主节点标记为客观下线状态(ODOWN)。
当 sentinel 判断主节点处于客观下线状态后,会触发故障转移。
4. 故障转移
发生故障转移时,会从监听主节点的 sentinel 中选举出主的 sentinel 来处理故障转移的过程。选举的过程类似于 Raft 协议,由标记客观下线的 sentinel 节点充当 candidate,向其他 sentinel 节点(follower)发起投票,当某个 candidate 从 follower 获得的票数超过一半后,该候选者就会成为 leader。而 sentinel 中的 epoch,配置纪元类似于 Raft 中的 term,每次选举后都会自增。主要过程为:
- 每个充当 candidate 的 sentinel 节点都会要求其他 sentinel 节点发送
is-master-down-addr
命令,将自己设置为 leader。 - 收到命令的 sentinel 节点,如果当前 epoch 和 candidate 传给他的 epoch 一样,说明他已经把自己的票投给了其他 candidate。投过票给别的 sentinel 后,在当前 epoch 内自己就只能成为 follower。如果该节点还没投过票,会采取先到先得的规则,将自己的票投给请求的 candidate 节点。
- 收到回复的 candidate 节点,会检查响应的 epoch 值和 leader_runid 值是否同自身的值一致,是的话则表示获得了一票。
- 当某个 candidate 节点获得半数以上的票数时,该节点便成为了 leader 节点。
- 如果一定时间内没法选举出 leader 节点,则每个 candidate 节点会等待随机时间后再次发起选举,知道选出 leader 节点为止。
选举出领头 sentinel 节点后,将由该节点处理故障转移,过程如下:
-
在已下线主节点的所有从节点中,选出一个从节点,将其转换为主节点。
主 sentinel 会按照下面的规则选择适合的 slave 节点上升为 master 节点:
1) 去除已下线的 slave 节点
2) 去除最近五秒内没有回复过主 sentinel 节点 INFO 信息的 slave 节点
3) 去除与已下线主节点连接断开超过 down-after-milliseconds*10 毫秒的 slave 节点
4) 根据各 slave 节点的优先级,从小到大排序,选择优先级最小的节点。对于相同优先级的节点,选择复制偏移量最大和 runid 最小的节点。
最后向被选择出来的 slave 节点发送
SLAVE OF NO ONE
命令。 - 向已下线主节点下的所有从节点发送 SLAVE OF 命令,改为复制新的主节点。
- 将已下线主节点设置为新主节点的从节点。
其中,上面步骤 1)中的 slave 节点优先级由 redis 配置文件中的 slave-priority N
选项控制。0 作为一个特殊的优先级,标识这个 slave 不能作为 master,所以一个优先级为 0 的 slave 永远不会被
哨兵挑选提升为 master。
上步骤 2) 中,从节点需要同步新的主节点的信息,期间会导致从节点不可用,可以通过
sentinel parallel-syncs mymaster <n>
来控制同时进行同步的从节点的数量。这个数字越小,完成故障转移所需的时间就越长,但是如果这个数字越大,就意味着越多的 slave 因为复制而不可用。
5. 脑裂时的数据一致性
Redis 不保证强一致性,在发生网络故障时,有可能出现脑裂。从脑裂发生到网络恢复正常,复制结束的这段时间里,异常主节点写入的数据将丢失。为了避免数据的丢失,可以对主节点增加如下配置:
min-slaves-to-write 1 #执行写操作所需的最少 slave 服务器数量,如果数量少于设定的值,写操作将被拒绝
min-slaves-max-lag 10 #网络延迟的最大时间,当写操作延迟大于所设定的时间,写操作将被拒绝
个人公众号:啊驼