0.前言
我们之前已经了解了redis的主从模式,主从模式是redis最基础的高可用模式,也确实一定程度上提高了redis的稳定性,但是主从模式也存在一些问题,比如如果主节点宕机的话,剩余的从节点只能用来读取数据却无法写入数据,这个可能会影响使用redis的系统。今天我们就来看下针对这种情况,redis另外一种更加高级的高可用解决方案,也就是redis的哨兵模式。redis哨兵模式引入了sentinel进程,用来监控redis主进程的运行情况,用以实现主节点的自动故障转移。
1.资源准备
因为redis哨兵模式中sentinel服务之间存在选举的过程,为了避免脑裂,最好部署单数个数的节点数,所以这次我们准备三个节点来部署redis哨兵模式,三台虚拟机的配置如下所示:
操作系统 | IP地址 | CPU | 内存 | redis版本 | 节点 |
---|---|---|---|---|---|
rocky9 linux | 192.168.159.167 | 4核 | 8G | 7.4 | 主节点 |
rocky9 linux | 192.168.159.168 | 4核 | 8G | 7.4 | 从节点 |
rocky9 linux | 192.168.159.171 | 4核 | 8G | 7.4 | 从节点 |
2.哨兵模式部署
根据我们以上虚拟机数量和配置信息,本次部署redis哨兵集群,需要先搭建一主两从的主从集群,之后修改redis哨兵模式相关配置,再启动sentinel服务。
2.1 搭建主从集群
我们首先在三个节点上部署单节点的redis,可以参考我之前的博客redis单节点部署操作手册,之后将这三个节点搭建成主从集群,可以参考我之前的这篇博客redis高可用之主从模式。
搭建完成之后,我们在主节点(192.168.159.167)查看一下集群信息:
cd /usr/local/redis/bin
./redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.159.168,port=6379,state=online,offset=64688,lag=0
slave1:ip=192.168.159.171,port=6379,state=online,offset=64688,lag=1
master_failover_state:no-failover
master_replid:7672078e5f197c6c19ea97b1898969b01ee56699
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:64688
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:64688
可以看到三个节点的redis主从集群搭建完成,其中192.168.159.168、192.168.159.171成功接入到192.168.159.167这个主节点。
2.2 修改sentinel配置
将sentinel.conf配置文件拷贝到redis配置文件目录下,三个节点都要执行如下命令:
cd ~/install/redis
cp redis-7.4.0/sentinel.conf /usr/local/redis/conf
修改sentinel配置文件,在三个节点上都要执行,修改配置项如下:
vim /usr/local/redis/conf/sentinel.conf
port 26379 // 端口
daemonize yes // 后台启动
pidfile /var/run/redis-sentinel.pid // pid文件
logfile "/usr/local/redis/logs/sentinel.log" // 日志文件
dir /usr/local/redis/data // 数据目录
sentinel monitor mymaster 192.168.159.167 6379 2 // 主节点信息和从节点个数
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
创建/lib/systemd/system/sentinel.service文件,文件内容如下:
[Unit]
Description=Redis Sentinel
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=forking
ExecStart=/usr/local/redis/bin/redis-sentinel /usr/local/redis/conf/sentinel.conf --supervised systemd
ExecStop=/bin/kill -s TERM $MAINPID
[Install]
WantedBy=multi-user.target
EOF
别忘了重新加载service文件,命令如下:
systemctl daemon-reload
2.3 启动sentinel
配置修改完成并且创建了service文件之后,就可以启动sentinel服务了,三个节点都要执行,命令如下:
systemctl start sentinel
启动完成之后检查下服务是否正常运行,在三个节点都可执行,命令如下:
ps -ef |grep sentinel
root 1801182 1 0 09:56 ? 00:00:00 /usr/local/redis/bin/redis-sentinel *:26379 [sentinel]
输出如上进程信息,说明sentinel正常运行。
2.4 查看哨兵信息
在主节点(192.168.159.167)查看下哨兵集群信息,命令如下:
cd /usr/local/redis/bin/
./redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.159.167:6379,slaves=2,sentinels=3
最后一行可以看到哨兵模式下有一个主节点,两个从节点以及三个sentinel节点,这些都是符合我们部署预期的。
3.故障转移测试
redis哨兵集群搭建完成之后,就可以开始故障转移测试了。
故障转移的步骤如下:
- 某个master发生故障,多个sentinel会监控到这个异常,这些sentinel会按照一定规则从多个slave中选中一个做为新的master,并通知别的slave从新的master中同步数据;
- 当某个slave转换为新的master,sentinel会记录新的master的地址信息和slave的地址信息,通知redis cli;
- redis cli接收到新的master和slave的信息,就会向新的master写入数据,从slave中读取数据;
- 等到原来的master重启之后,会变成新的master的slave,并从新的master同步数据。 根据故障转移步骤,我们先停止主节点redis服务,在主节点(192.168.159.167)执行如下命令:
systemctl stop redis
然后查看从节点哨兵信息,在两个从节点上分别执行如下命令:
./redis-cli -p 26379
127.0.0.1:26379> info sentinel
节点一输出信息如下:
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.159.171:6379,slaves=2,sentinels=3
节点二输出信息如下:
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.159.171:6379,slaves=2,sentinels=3
可以看到在老的主节点(192.168.159.167)停止之后,sentinel选定的新的主节点是192.168.159.171,完成了主节点的故障转移。
我们再重启一下原来的主节点(192.168.159.167),看是否会议从节点的方式重新加入到集群中,在192.168.159.167执行如下命令:
systemctl start redis
redis服务正常启动之后,我们再到新的主节点(192.168.159.171)查看redis集群信息,在192.168.159.171执行如下命令:
cd /usr/local/redis/bin
./redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.159.168,port=6379,state=online,offset=440454,lag=1
slave1:ip=192.168.159.167,port=6379,state=online,offset=440454,lag=1
master_failover_state:no-failover
master_replid:769a56accce1ecc744108a8047204bc8b9d29a89
master_replid2:7672078e5f197c6c19ea97b1898969b01ee56699
master_repl_offset:440454
second_repl_offset:315056
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:64633
repl_backlog_histlen:375822
可以看到192.168.159.167以从节点的形式重新加入到了集群当中。
到此为止,整个故障转移过程就验证完成了,确实是按照既定的流程运行的。
4.故障转移原理
前面带着大家搭建了整个哨兵集群,并且验证了故障转移的整个过程,下面我们来看下故障转移的原理。
4.1 监控逻辑图
哨兵集群监控的逻辑图如下:
根据官方文档的说明,哨兵模式包含监控、自动故障转移、配置提供者、通知这四大功能:
- 监控(monitoring):哨兵会不断地检查主节点和从节点是否运作正常;
- 自动故障转移(Automatic failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点;
- 配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址;
- 通知(Notification):哨兵可以将故障转移的结果发送给客户端。 结合以上功能,哨兵模式最终实现了故障转移。
4.2 哨兵集群通信
在哨兵模式中,哨兵之间的通信是通过redis提供的pub/sub机制实现的,在主从集群中,主库上有一个名为__sentinel__:hello
的频道,不同哨兵就是通过它来相互发现,互相通信的。
如上图所示,哨兵 1 把自己的 IP(192.168.159.167)和端口(26379)发布到
__sentinel__:hello
频道上,哨兵 2 和 3 订阅了该频道。那么此时,哨兵 2 和 3 就可以从这个频道直接获取哨兵 1 的 IP 地址和端口号。然后,哨兵 2、3 可以和哨兵 1 建立网络连接。
4.3 哨兵监控原理
哨兵在工作过程中,又是如何监控集群中主从节点的呢,其实主要是向主节点发送info命令,通过info命令获取从节点的信息,之后和从节点建立连接,并在这个连接上持续的对从库进行监控。
4.4 主库选择原理
在主节点出现异常宕机之后,我们来看下哨兵是如何选择新的节点成为主节点的。
4.4.1 主库下线
主库下线分为主观下线和客观下线:
- 主观下线:任何一个哨兵都是可以监控探测,并作出redis节点下线的判断;
- 客观下线:由哨兵集群共同决定redis节点是否下线;
当某个哨兵判断主库主观下线后,会给其他哨兵发送
is-master-down-by-addr
命令,其他哨兵会根据自己和主库的连接情况,判断主库是否下线,如果下线,则做出"Y"的响应(表示赞同)或者"N"的响应(表示反对),如果赞成票大于哨兵配置文件中的quorum配置项,就判定主库客观下线了。
4.4.2 哨兵选举
当主库客观下线后,由哪个哨兵节点来执行主从切换呢,这个就涉及到哨兵集群的选举机制了。哨兵的选举机制就是一个raft推荐算法,也即当节点获取票数大于num(sentinels)/2+1时,该节点成为Leader(领导者),如果没有超过,则继续选举。 哨兵节点想成为Leader,必须满足两个条件:
- 拿到半数以上的赞成票;
- 拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值 比如,我们这次哨兵节点数为3,quorum值设置为2,那么只要哨兵节点拿到2票,就可以成为Leader节点。
4.4.3 选择新主库
哨兵Leader节点选择新主库的原则有:
- 过滤掉不健康的(下线或断线),没有回复过哨兵ping响应的从节点;
- 选择
salve-priority
从节点优先级最高(redis.conf)的; - 选择复制偏移量最大,只复制最完整的从节点。 结合以上原则,Leader节点就可以在剩余从节点中选择新的主节点了,之后由新的主节点对外提供写操作,并将新的数据同步给其他从节点,而连接哨兵模式集群的服务也会连接新的主节点,实现无影响故障转移。
5.总结
哨兵模式是基于主从模式实现的一种高可用模式,可以自动实现故障转移。通过以上实践,可以发现哨兵模式的搭建和使用并不复杂,但是实现原理涉及到共识算法Raft算法,以及哨兵节点之间的通信和哨兵节点同主从库之间的通信,内容还是很丰富的,大家可以慢慢理解。