Redis进阶 - 高可用:哨兵机制(Sentinel)
本文讲解哨兵模式。
介绍
Redis Sentinel,即Redis哨兵,在Redis 2.8版本开始引入。哨兵的核心功能是主节点的自动故障转移。
假设你用了 Redis(一个内存数据库)来做缓存或快速数据读写。那如果这个 Redis 的主 (master)节点突然挂了,怎么办呢?数据停了、服务挂了…这就很糟糕。
为了解决这个问题,Redis 提供了一个机制,叫做 Redis Sentinel(哨兵机制)。它可以:
- 监控 Redis 的主从节点,看看谁坏了。
- 当主节点坏了,自动切换一个从 (slave)节点变成新的主节点。
- 通知客户端:原来的主节点挂了、新主节点是谁。
- 帮客户端找到“当前哪台是主节点”。
下图是一个典型的哨兵集群监控的逻辑图:

哨兵集群的组建原理
哨兵实例之间可以相互发现,要归功于 Redis 提供的 pub/sub 机制。
在主从集群中,主库上有一个名为__sentinel__:hello的频道,不同哨兵就是通过它来相互发现,实现互相通信的。在下图中,哨兵 1 把自己的 IP(172.16.19.3)和端口(26579)发布到__sentinel__:hello频道上,哨兵 2 和 3 订阅了该频道。那么此时,哨兵 2 和 3 就可以从这个频道直接获取哨兵 1 的 IP 地址和端口号。有了ip地址,那么哨兵们可以建立网络连接。

通过这个方式,哨兵 2 和 3 也可以建立网络连接,这样一来,哨兵集群就形成了。它们相互间可以通过网络连接进行通信,比如说对主库有没有下线这件事儿进行判断和协商。
哨兵监控Redis库
哨兵监控什么呢?怎么监控呢?
- 主节点(master):主节点负责处理写操作,监控主节点是否挂了,时刻保持服务高可用。
- 从节点(slave):复制主节点的数据,用于读取或备份,主节点挂了从节点可以选举为主节点。
监控是哨兵向主库发送 INFO 命令来完成的, 哨兵通过这个命令拿到 Redis 节点当前的运行状态。
哨兵与Redis建立连接:如下图所示,哨兵 2 给主库发送 INFO 命令,主库接受到这个命令后,就会把从库列表(Slave)返回给哨兵。接着,哨兵就可以根据从库列表中的连接信息,和每个从库建立连接,并在这个连接上持续地对从库进行监控。哨兵 1 和 3 可以通过相同的方法和从库建立连接。

主库下线的判定
哨兵如何判断主库已经下线了呢?
首先要理解两个概念:主观下线和客观下线
- 主观下线:任何一个哨兵都是可以监控探测,并作出Redis节点下线的判断;单个哨兵判断出下线。
- 客观下线:有哨兵集群共同决定Redis节点是否下线, 当客观下线成立,主库会被换掉。
当某个哨兵(如下图中的哨兵2)判断主库“主观下线”后,就会给其他哨兵发送 is-master-down-by-addr 命令。接着,其他哨兵会根据自己和主库的连接情况,做出 Y 或 N 的响应,Y 相当于赞成票,N 相当于反对票。

如果赞成票数(这里是2)是大于等于哨兵配置文件中的 quorum 配置项(比如这里如果是quorum=2), 则可以判定主库客观下线了。
哨兵集群的选举
判断完主库下线后,由哪个哨兵节点来执行主从切换呢?这里就需要哨兵集群的选举机制了。
选举出来的 leader 会执行主从切换的任务。
- 选举过程:
- 每个 Sentinel 都可以向其他 Sentinel 发送一个为自己投票的命令(
SENTINEL is-master-down-by-addr)。 - 在配置的超时时间内,率先获得超过半数(
quorum配置的数)选票的 Sentinel 成为领导者。 - 这是一个 Raft-like 的分布式共识算法,保证了在任何时候,最多只有一个领导者。
-
任何一个想成为 Leader 的哨兵,要满足两个条件:
-
第一,拿到半数以上的赞成票;
-
第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值。
新主库的选出
主库既然判定客观下线了,那么如何从剩余的从库中选择一个新的主库呢?
- 过滤掉不健康的(下线或断线),没有回复过哨兵ping响应的从节点
- 选择
salve-priority从节点优先级最高(redis.conf)的 - 选择复制偏移量最大,只复制最完整的从节点

只能选出一个主库,如果有选出来两个主库,这就叫做脑裂。
故障转移
故障转移 : 意思是把故障的节点切换到另一个健康的节点,上一步选举出来主库,这一步要做故障转移,自动恢复 Redis 的服务。
假设根据我们一开始的图:(我们假设:判断主库客观下线了,同时选出sentinel 3是哨兵 leader )

故障转移流程如下:

- 将slave-1脱离原从节点(PS: 5.0 中应该是
replicaof no one),升级主节点, - 将从节点slave-2指向新的主节点
- 通知客户端主节点已更换
- 将原主节点(oldMaster)变成从节点,指向新的主节点
转移之后

