从入门到精通【Redis】初识Redis哨兵机制(Sentinel)
文章目录
- 📕1. 相关名词解释
- 📕2. 对比人工恢复与哨兵恢复主节点的过程
- ✏️2.1 ⼈⼯恢复主节点过程
- ✏️2.2 哨兵恢复主节点过程
- 📕3. 基于Docker快速安装部署
- ✏️3.1 准备工作
- ✏️3.2 编排 redis 主从节点
- ✏️3.3 编排 redis-sentinel 节点
- 📕4. 选举原理
特此注明 :
Designed By :长安城没有风
Version:1.0
Time:2025.10.09
Location:辽宁 · 大连
Redis 的主从复制模式下,⼀旦主节点由于故障不能提供服务,需要⼈⼯进⾏主从切换,同时⼤量的客户端需要被通知切换到新的主节点上,对于上了⼀定规模的应⽤来说,这种⽅案是⽆法接受的,于是 Redis 从 2.8 开始提供了 Redis Sentinel(哨兵)方案来解决这个问题。本篇文章会给大家简单介绍一下Redis Sentinel方案
📕1. 相关名词解释
Redis Sentinel 是 Redis 的⾼可⽤实现⽅案,在实际的⽣产环境中,对提⾼整个系统的⾼可⽤是⾮常有帮助的,由于对 Redis 的许多概念都有不同的名词解释,所以在介绍 Redis Sentinel 之前,先对⼏个名词概念进⾏必要的说明。
名词 | 逻辑结构 | 物理结构 |
---|---|---|
主节点 | Redis 主服务 | ⼀个独⽴的 redis-server 进程 |
从节点 | Redis从服务 | ⼀个独⽴的 redis-server 进程 |
Redis 数据节点 | 主从节点 | 主节点和从节点的进程 |
哨兵节点 | 监控 Redis 数据节点的节点 | ⼀个独⽴的 redis-sentinel 进程 |
哨兵节点集合 | 若⼲哨兵节点的抽象组合 | 若⼲ redis-sentinel 进程 |
Redis 哨兵(Sentinel) | Redis 提供的⾼可⽤⽅案 | 哨兵节点集合 和 Redis 主从节点 |
应⽤⽅ | 泛指⼀个或多个客户端 | ⼀个或多个连接 Redis 的进程 |
📕2. 对比人工恢复与哨兵恢复主节点的过程
✏️2.1 ⼈⼯恢复主节点过程
1. 运维⼈员通过监控系统,发现 Redis 主节点故障宕机。
2. 运维⼈员从所有节点中,选择⼀个(此处选择了 slave 1)执⾏ slaveof no one,使其作为新的主节点。
3. 运维⼈员让剩余从节点(此处为 slave 2)执⾏ slaveof {newMasterIp} {newMasterPort} 从新主节点开始数据同步。
4. 更新应⽤⽅连接的主节点信息到 {newMasterIp} {newMasterPort}。
5. 如果原来的主节点恢复,执⾏ slaveof {newMasterIp} {newMasterPort} 让其成为⼀个从节点。
✏️2.2 哨兵恢复主节点过程
Redis Sentinel 架构
Redis Sentinel 相⽐于主从复制模式是多了若⼲(建议保持奇数)Sentinel 节点⽤于实现监控数据节点,哨兵节点会定期监控所有节点(包含数据节点和其他哨兵节点)。针对主节点故障的情况,故障转移流程⼤致如下:
- 主节点故障,从节点同步连接中断,主从复制停⽌。
- 哨兵节点通过定期监控发现主节点出现故障。哨兵节点与其他哨兵节点进⾏协商,达成多数认同主节点故障的共识。(这步主要是防⽌该情况:出故障的不是主节点,⽽是发现故障的哨兵节点,该情况经常发⽣于哨兵节点的⽹络被孤⽴的场景下)
- 哨兵节点之间使⽤ Raft 算法选举出⼀个领导⻆⾊,由该节点负责后续的故障转移⼯作。
- 哨兵领导者开始执⾏故障转移:从节点中选择⼀个作为新主节点;让其他从节点同步新主节点;通知应⽤层转移到新主节点。
通过上⾯的介绍,可以看出 Redis Sentinel 具有以下⼏个功能:
- 监控: Sentinel 节点会定期检测 Redis 数据节点、其余哨兵节点是否可达。
- 故障转移: 实现从节点晋升(promotion)为主节点并维护后续正确的主从关系。
- 通知: Sentinel 节点会将故障转移的结果通知给应⽤⽅。
📕3. 基于Docker快速安装部署
✏️3.1 准备工作
1. 安装 docker 和 docker-compose
2. 停⽌之前的 redis-server
# 停⽌ redis-server
service redis-server stop
3. 使⽤ docker 获取 redis 镜像
docker pull redis:5.0.9
✏️3.2 编排 redis 主从节点
1. 编写 docker-compose.yml
创建 /root/redis/docker-compose.yml , 同时 cd 到 yml 所在⽬录中。
注意 : docker 中可以通过容器名字, 作为 ip 地址, 进⾏相互之间的访问。
version: '3.7'
services:master:image: 'redis:5.0.9'container_name: redis-masterrestart: alwayscommand: redis-server --appendonly yesports: - 6379:6379- slave1:image: 'redis:5.0.9'container_name: redis-slave1restart: alwayscommand: redis-server --appendonly yes --slaveof redis-master 6379ports:- 6380:6379- slave2:image: 'redis:5.0.9'container_name: redis-slave2restart: alwayscommand: redis-server --appendonly yes --slaveof redis-master 6379ports:- 6381:6379
2. 启动所有容器
docker-compose up -d
如果启动后发现前⾯的配置有误,需要重新操作,使⽤ docker-compose down 即可停⽌并删除刚才创建好的容器。
3. 查看运⾏⽇志
docker-compose logs
上述操作必须保证⼯作⽬录在 yml 的同级⽬录中,才能⼯作。
✏️3.3 编排 redis-sentinel 节点
也可以把 redis-sentinel 放到和上⾯的 redis 的同⼀个 yml 中进⾏容器编排,此处分成两组,主要是为了两⽅⾯:
- 观察⽇志⽅便
- 确保 redis 主从节点启动之后才启动 redis-sentinel,如果先启动 redis-sentinel 的话,可能触发额外的选举过程,混淆视听。(不是说先启动哨兵不⾏,⽽是观察的结果可能存在⼀定随机性。)
1. 编写 docker-compose.yml
创建 /root/redis-sentinel/docker-compose.yml,同时 cd 到 yml 所在⽬录中。
注意 : 每个⽬录中只能存在⼀个 docker-compose.yml ⽂件
version: '3.7'services:sentinel1:image: 'redis:5.0.9'container_name: redis-sentinel-1restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel1.conf:/etc/redis/sentinel.confports:- 26379:26379sentinel2:image: 'redis:5.0.9'container_name: redis-sentinel-2restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel2.conf:/etc/redis/sentinel.confports:- 26380:26379sentinel3:image: 'redis:5.0.9'container_name: redis-sentinel-3restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel3.conf:/etc/redis/sentinel.confports:- 26381:26379networks:default:external:name: redis-data_default
2. 创建配置⽂件
创建 sentinel1.conf ,sentinel2.conf ,sentinel3.conf,三份⽂件的内容完全相同,都放到 /root/redis-sentinel/ ⽬录中。(redis-sentinel 在运⾏中可能会对配置进⾏ rewrite, 修改⽂件内容. 如果⽤⼀份⽂件, 就可能出现修改混乱的情况.)
bind 0.0.0.0
port 26379
sentinel monitor redis-master redis-master 6379 2
sentinel down-after-milliseconds redis-master 1000
sentinel monitor 主节点名 主节点ip 主节点端⼝ 法定票数
- 主节点名:哨兵内部⾃⼰起的名字
- 主节点 ip:部署 redis-master 的设备 ip,此处由于是使⽤ docker,可以直接写 docker 的容器名,会被⾃动 DNS 成对应的容器 ip。
- 主节点端⼝:我猜大家一定都能理解端口是啥意思了
- 法定票数:哨兵需要判定主节点是否挂了,但是有的时候可能因为特殊情况,⽐如主节点仍然⼯作正常,但是哨兵节点⾃⼰⽹络出问题了,⽆法访问到主节点了,此时就可能会使该哨兵节点认为主节点下线,出现误判,使⽤投票的⽅式来确定主节点是否真的挂了是更稳妥的做法,需要多个哨兵都认为主节点挂了,票数 >= 法定票数 之后,才会真的认为主节点是挂了。
sentinel down-after-milliseconds 自定义时间
主节点和哨兵之间通过⼼跳包来进⾏沟通,如果⼼跳包在指定的时间内还没回来,就视为是节点出现故障。
3. 启动所有容器
docker-compose up -d
如果启动后发现前⾯的配置有误,需要重新操作,使⽤ docker-compose down 即可停⽌并删除刚才创建好的容器。
4. 查看运行日志
docker-compose logs
上述操作必须保证⼯作⽬录在 yml 的同级⽬录中,才能⼯作。
📕4. 选举原理
假定当前环境如上⽅介绍,三个哨兵(sentenal1, sentenal2, sentenal3),⼀个主节点(redis-master),两个从节点(redis-slave1,redis-slave2)。当主节点出现故障,就会触发重新⼀系列过程。
1. 主观下线
当 redis-master 宕机,此时 redis-master 和三个哨兵之间的⼼跳包就没有了,此时,站在三个哨兵的⻆度来看,redis-master 出现严重故障,因此三个哨兵均会把 redis-master 判定为主观下线 (SDown)。
2. 客观下线
哨兵 sentenal1,sentenal2,sentenal3 均会对主节点故障这件事情进⾏投票,当故障得票数 >= 配置的法定票数之后,此时意味着 redis-master 故障这个事情被做实了,此时触发客观下线 (ODown)。
3. 选举出哨兵的 leader
选举过程涉及到 Raft 算法
假定⼀共三个哨兵节点, S1, S2, S3
-
每个哨兵节点都给其他所有哨兵节点,发起⼀个 “拉票请求”。 (S1 -> S2, S1 -> S3, S2 -> S1, S2 -> S3, S3 -> S1, S3 -> S2)
-
收到拉票请求的节点,会回复⼀个 “投票响应”,响应的结果有两种可能,投 or 不投。
⽐如 S1 给 S2 发了个投票请求,S2 就会给 S1 返回投票响应。到底 S2 是否要投 S1 呢? 取决于 S2 是否给别⼈投过票了(每个哨兵只有⼀票),如果 S2 没有给别⼈投过票,换⽽⾔之,S1 是第⼀个向 S2 拉票的,那么 S2 就会投 S1,否则就不投。
- ⼀轮投票完成之后,发现得票超过半数的节点,⾃动成为 leader。
如果出现平票的情况 (S1 投 S2, S2 投 S3, S3 投 S1, 每⼈⼀票),就重新再投⼀次即可,这也是为啥建议哨兵节点设置成奇数个的原因,如果是偶数个,则增⼤了平票的概率,带来不必要的开销。
- leader 节点负责挑选⼀个 slave 成为新的 master,当其他的 sentenal 发现新的 master 出现了,就说明选举结束了。
4. leader 挑选出合适的 slave 成为新的 master
挑选规则:
- ⽐较优先级,优先级⾼(数值⼩的)的上位,优先级是配置⽂件中的配置项( slave-priority 或者replica-priority )。
- ⽐较 replication offset 谁复制的数据多,⾼的上位。
- ⽐较 run id,谁的 id ⼩,谁上位。
当某个 slave 节点被指定为 master 之后:
- leader 指定该节点执⾏ slave no one ,成为 master。
- leader 指定剩余的 slave 节点,都依附于这个新 master。