redis高可用之哨兵模式

开发与运维NoSQL数据库

0.前言

我们之前已经了解了redis的主从模式,主从模式是redis最基础的高可用模式,也确实一定程度上提高了redis的稳定性,但是主从模式也存在一些问题,比如如果主节点宕机的话,剩余的从节点只能用来读取数据却无法写入数据,这个可能会影响使用redis的系统。今天我们就来看下针对这种情况,redis另外一种更加高级的高可用解决方案,也就是redis的哨兵模式。redis哨兵模式引入了sentinel进程,用来监控redis主进程的运行情况,用以实现主节点的自动故障转移。

1.资源准备

因为redis哨兵模式中sentinel服务之间存在选举的过程,为了避免脑裂,最好部署单数个数的节点数,所以这次我们准备三个节点来部署redis哨兵模式,三台虚拟机的配置如下所示:

操作系统IP地址CPU内存redis版本节点
rocky9 linux192.168.159.1674核8G7.4主节点
rocky9 linux192.168.159.1684核8G7.4从节点
rocky9 linux192.168.159.1714核8G7.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 监控逻辑图

哨兵集群监控的逻辑图如下:

picture.image 根据官方文档的说明,哨兵模式包含监控、自动故障转移、配置提供者、通知这四大功能:

  • 监控(monitoring):哨兵会不断地检查主节点和从节点是否运作正常;
  • 自动故障转移(Automatic failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点;
  • 配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址;
  • 通知(Notification):哨兵可以将故障转移的结果发送给客户端。 结合以上功能,哨兵模式最终实现了故障转移。

4.2 哨兵集群通信

在哨兵模式中,哨兵之间的通信是通过redis提供的pub/sub机制实现的,在主从集群中,主库上有一个名为__sentinel__:hello的频道,不同哨兵就是通过它来相互发现,互相通信的。

picture.image 如上图所示,哨兵 1 把自己的 IP(192.168.159.167)和端口(26379)发布到__sentinel__:hello频道上,哨兵 2 和 3 订阅了该频道。那么此时,哨兵 2 和 3 就可以从这个频道直接获取哨兵 1 的 IP 地址和端口号。然后,哨兵 2、3 可以和哨兵 1 建立网络连接。

4.3 哨兵监控原理

哨兵在工作过程中,又是如何监控集群中主从节点的呢,其实主要是向主节点发送info命令,通过info命令获取从节点的信息,之后和从节点建立连接,并在这个连接上持续的对从库进行监控。

picture.image

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算法,以及哨兵节点之间的通信和哨兵节点同主从库之间的通信,内容还是很丰富的,大家可以慢慢理解。

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
字节跳动 NoSQL 的实践与探索
随着 NoSQL 的蓬勃发展越来越多的数据存储在了 NoSQL 系统中,并且 NoSQL 和 RDBMS 的界限越来越模糊,各种不同的专用 NoSQL 系统不停涌现,各具特色,形态不一。本次主要分享字节跳动内部和火山引擎 NoSQL 的实践,希望能够给大家一定的启发。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论