Redis Sentinel 哨兵架构
一、哨兵架构
主从架构存在以下两个问题
- 手工故障转移
- 写性能和存储能力受限
而 Redis Sentinel 具有以下主要功能:
- 监控:Sentinel 会定期监控 Redis 数据节点、以及其余 Sentinel 节点是否可达
- 通知:Sentinel 会将故障转移的结果通知给应用方
- 故障转移:当主节点故障后,从节点自动选举晋升并维护后续主从关系
- 配置提供:为客户端提供 Sentinel 节点集合,从中选举主节点
二、环境配置
节点环境
- 1 Master 节点
- 2 Slave 节点
- 3 Sentinel 节点
目录结构
[root@bj-vmware-test1 redis]# tree .
.
├── config
│ ├── redis_server_6379.conf
│ └── sentinel_26379.conf
├── data
│ ├── 26379.log
│ ├── 6379.aof
│ ├── 6379.log
│ └── 6379.rdb
└── run
└── redis_6379.pid
master 节点配置文件
root@iZ947mgy3c5Z:/prodata/redis# cat config/redis_server_6379.conf
daemonize yes
port 6379
bind 127.0.0.1
dbfilename "6379.rdb"
appendfilename "6379.aof"
dir "/prodata/redis/data"
logfile "/prodata/redis/data/6379.log"
pidfile "/prodata/redis/run/redis_6379.pid"
appendonly yes
slave 节点配置文件
root@iZ947mgy3c5Z:/prodata/redis# cat config/redis_server_6379.conf
daemonize yes
port 6379
bind 127.0.0.1
dbfilename "6379.rdb"
appendfilename "6379.aof"
dir "/prodata/redis/data"
logfile "/prodata/redis/data/6379.log"
pidfile "/prodata/redis/run/redis_6379.pid"
appendonly yes
# 设置主节点地址端口
slaveof 192.168.2.20 6379
启动集群,主、从节点分别执行
$ redis-server config/redis_server_6379.conf
三、哨兵配置
最基础的哨兵配置
root@iZ947mgy3c5Z:/prodata/redis# cat config/sentinel_26379.conf
port 26379
daemonize yes
dir "/prodata/redis/data"
logfile "26379.log"
# 设置主节点地址端口
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
配置参数
sentinel monitor:配置主从复制主节点名称,以及 ip、端口,以及 quorum (法定人数),此处配置为 2,代表 >=2个 sentinel 节点认为宕机,才会触发自动 failover,否则不会进行 failoversentinel down-after-milliseconds:sentinel 每秒向监控的 redis 发送 ping 命令,如果响应时间超过 30 秒,则认为 master 宕机,随后,进入法定票数判断首先,Sentinel 标记 master 节点为 主观下线(Subjectively Down, 简称
SDown),如果标记 master 实例的 sentinel 数超过 quorum,则将该实例标记为 客观下线(Objectively Down,简称ODown),如果没超过 quorum 则清除该 redis 实例的主观下线标记sentinel parallel-syncs:当发生 failover 后,最多允许几个 slave 同时向新选举出的 master 复制数据,默认建议设置 1,同一时间只有一台处于重新复制新主数据状态(无法提供服务),其余节点排队等待重新复制新主数据(可以提供服务)- 参数值过小:并发复制的实例数越少,完成整个主从架构的故障转移需要的时间越长
- 参数值过大:大量从节点并发复制数据,导致短时间内无法提供读请求的响应
sentinel failover-timeout:如果整个 failover 过程超过指定毫秒,则认为本次 failover 失败
启动哨兵实例
$ redis-sentinel /prodata/redis/config/sentinel_26379.conf
四、模拟故障
通过 kill 命令结束 redis-server 进程
kill -9 redis_pid
Sentinel 节点 1 宕机日志
# 标记 master 节点为 主观下线 SDown
2236:X 05 Jan 17:30:50.758 # +sdown master mymaster 192.168.2.50 6379
# 法定票数超过 2 票,客观下线 ODown
2236:X 05 Jan 17:30:50.825 # +odown master mymaster 192.168.2.50 6379 #quorum 2/2
# 进入新纪元
2236:X 05 Jan 17:30:50.825 # +new-epoch 4
# 开始故障转移
2236:X 05 Jan 17:30:50.825 # +try-failover master mymaster 192.168.2.50 6379
# 投票
2236:X 05 Jan 17:30:50.828 # +vote-for-leader 4aa9c09483ec5fd8ffcce32159bc76168e8e4104 4
2236:X 05 Jan 17:30:50.835 # 192.168.2.30:26379 voted for 4aa9c09483ec5fd8ffcce32159bc76168e8e4104 4
2236:X 05 Jan 17:30:50.836 # 192.168.2.50:26379 voted for 4aa9c09483ec5fd8ffcce32159bc76168e8e4104 4
2236:X 05 Jan 17:30:50.895 # +elected-leader master mymaster 192.168.2.50 6379
2236:X 05 Jan 17:30:50.895 # +failover-state-select-slave master mymaster 192.168.2.50 6379
# 从 slave 节点中选择 192.168.2.30 作为待晋升 slave 节点
2236:X 05 Jan 17:30:50.986 # +selected-slave slave 192.168.2.30:6379 192.168.2.30 6379 @ mymaster 192.168.2.50 6379
2236:X 05 Jan 17:30:50.986 * +failover-state-send-slaveof-noone slave 192.168.2.30:6379 192.168.2.30 6379 @ mymaster 192.168.2.50 6379
2236:X 05 Jan 17:30:51.039 * +failover-state-wait-promotion slave 192.168.2.30:6379 192.168.2.30 6379 @ mymaster 192.168.2.50 6379
2236:X 05 Jan 17:30:52.028 # +promoted-slave slave 192.168.2.30:6379 192.168.2.30 6379 @ mymaster 192.168.2.50 6379
2236:X 05 Jan 17:30:52.028 # +failover-state-reconf-slaves master mymaster 192.168.2.50 6379
2236:X 05 Jan 17:30:52.030 * +slave-reconf-sent slave 192.168.2.20:6379 192.168.2.20 6379 @ mymaster 192.168.2.50 6379
2236:X 05 Jan 17:30:52.977 * +slave-reconf-inprog slave 192.168.2.20:6379 192.168.2.20 6379 @ mymaster 192.168.2.50 6379
2236:X 05 Jan 17:30:52.977 * +slave-reconf-done slave 192.168.2.20:6379 192.168.2.20 6379 @ mymaster 192.168.2.50 6379
# 清除 ODown 客观下线标记
2236:X 05 Jan 17:30:53.047 # -odown master mymaster 192.168.2.50 6379
# 故障转移结束
2236:X 05 Jan 17:30:53.047 # +failover-end master mymaster 192.168.2.50 6379
# 切换新主为 192.168.2.30
2236:X 05 Jan 17:30:53.047 # +switch-master mymaster 192.168.2.50 6379 192.168.2.30 6379
# 其余两个节点作为 192.168.2.30 的从节点
2236:X 05 Jan 17:30:53.048 * +slave slave 192.168.2.20:6379 192.168.2.20 6379 @ mymaster 192.168.2.30 6379
2236:X 05 Jan 17:30:53.048 * +slave slave 192.168.2.50:6379 192.168.2.50 6379 @ mymaster 192.168.2.30 6379
Sentinel 节点 2 宕机日志
[root@Da redis]# tail -f data/26379.log
31724:X 10 Jan 10:51:38.196 # +sdown master mymaster 192.168.2.50 6379
31724:X 10 Jan 10:51:38.267 # +new-epoch 4
31724:X 10 Jan 10:51:38.269 # +vote-for-leader 4aa9c09483ec5fd8ffcce32159bc76168e8e4104 4
31724:X 10 Jan 10:51:38.280 # +odown master mymaster 192.168.2.50 6379 #quorum 3/2
31724:X 10 Jan 10:51:38.280 # Next failover delay: I will not start a failover before Wed Jan 10 10:57:39 2018
31724:X 10 Jan 10:51:39.467 # +config-update-from sentinel 192.168.2.20:26379 192.168.2.20 26379 @ mymaster 192.168.2.50 6379
31724:X 10 Jan 10:51:39.467 # +switch-master mymaster 192.168.2.50 6379 192.168.2.30 6379
31724:X 10 Jan 10:51:39.468 * +slave slave 192.168.2.20:6379 192.168.2.20 6379 @ mymaster 192.168.2.30 6379
31724:X 10 Jan 10:51:39.468 * +slave slave 192.168.2.50:6379 192.168.2.50 6379 @ mymaster 192.168.2.30 6379
31724:X 10 Jan 10:52:09.470 # +sdown slave 192.168.2.50:6379 192.168.2.50 6379 @ mymaster 192.168.2.30 6379
Sentinel 节点 3 宕机日志
5592:X 10 Jan 10:51:38.164 # +sdown master mymaster 192.168.2.50 6379
5592:X 10 Jan 10:51:38.276 # +new-epoch 4
5592:X 10 Jan 10:51:38.278 # +vote-for-leader 4aa9c09483ec5fd8ffcce32159bc76168e8e4104 4
5592:X 10 Jan 10:51:39.233 # +odown master mymaster 192.168.2.50 6379 #quorum 3/2
5592:X 10 Jan 10:51:39.234 # Next failover delay: I will not start a failover before Wed Jan 10 10:57:39 2018
5592:X 10 Jan 10:51:39.476 # +config-update-from sentinel 192.168.2.20:26379 192.168.2.20 26379 @ mymaster 192.168.2.50 6379
5592:X 10 Jan 10:51:39.478 # +switch-master mymaster 192.168.2.50 6379 192.168.2.30 6379
5592:X 10 Jan 10:51:39.479 * +slave slave 192.168.2.20:6379 192.168.2.20 6379 @ mymaster 192.168.2.30 6379
5592:X 10 Jan 10:51:39.481 * +slave slave 192.168.2.50:6379 192.168.2.50 6379 @ mymaster 192.168.2.30 6379
5592:X 10 Jan 10:52:09.518 # +sdown slave 192.168.2.50:6379 192.168.2.50 6379 @ mymaster 192.168.2.30 6379
五、实现原理
1. 三个定时任务
- Sentinel 定期向主、从节点发送info命令获取最新拓扑数据。
- 简化配置
- 动态发现从节点、更新拓扑
- Sentinel 定期汇报主节点以及自身情况到
__sentinel__:hello频道,所有 sentinel 都会订阅这个频道,来了解其他 sentinel 情况以及它们对主节点的判断- 动态发现 sentinel 节点
- sentinel 交换主节点情况,为后续客观下线和选举做准备。
- Sentinel 定期想主、从节点、以及其他Sentinel节点发送ping包,以及检测所有节点健康情况
2. 主观下线、客观下线
当第三个定期任务 ping 心跳检测失败超过 down-after-milliseconds 没有得到有效回复后,Sentinel 会对该节点做失败认定,即 主观下线 SDown,主观下线仅代表当前 sentinel 一家之言,有可能存在误判
当 Sentinel 主观下线的节点是主节点时,该 Sentinel 节点会通过sentinel is-master-down-by-addr命令向其它 sentinel 节点询问该 master 节点的状态,当其它节点赞同数超过 <quorum> 个数时,此时 sentinel 节点间会达成共识,由该 Sentinel 做 客观下线 ODown 的决定
3. 领导者选举
故障转移的工作只需要一个 Sentinel 就可以完成了,所以这里需要选举一个出来
- 主观下线后,执行
sentinel is-master-down-by-addr命令时,要求自己成为领导者 - 收到命令的 Sentinel 节点如果没有同意过
sentinel is-master-down-by-addr,则同意该请求,否则拒绝 - 如果该 Sentinel 发现自己票数已经大于等于
max(quorum, num(sentinels) / 2 + 1),那么它就晋升为领导者 - 如果没有选举出领导者,则进入下一轮选举
4. 故障转移
领导者 Sentinel 负责故障转移
- 选择可用从节点
- 过滤从节点列表中不健康的、5s内没有回复过ping的、断开超过
down-after-milliseconds* 10 秒的。 - 选择
slave-priority最高的从节点列表,如果存在则返回 - 选择复制偏移量最大的从节点(复制的最完整),如果存在则返回
- 选择runid最小的从节点
- 完毕
- 过滤从节点列表中不健康的、5s内没有回复过ping的、断开超过
- 从节点升级
- 在选择出的从节点执行
slaveof no one
- 在选择出的从节点执行
- 更新主从关系
- 向其余从节点发送命令,让他们成为新主的从节点,复制规则和
parallel-syncs有关
- 向其余从节点发送命令,让他们成为新主的从节点,复制规则和
- 更新主从配置集合
- Sentinel节点集合将原主标记为从节点,并保持关注,当其恢复时命令它复制新主数据
六、哨兵优化
误判控制
down-after-milliseconds: 不可达时间阈值,这会带来矛盾的问题,所以要结合网络情况来配置,不稳定的环境,频繁不稳定建议配置大一些,如果网路稳定则配置小些
过大则导致发现故障和转移故障时间长
从而导致应用方故障时间也拉长
##七、遗留问题
Sentinel 解决了 Master、Slave 节点的可用性问题,但是也留下的几个问题
- 数据存储容量无法水平扩展(Sentinel 集群添加从节点只会提升 读请求 性能)
- 写请求性能无法水平扩展