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 集群添加从节点只会提升 读请求 性能)
- 写请求性能无法水平扩展