引言
Redis是一款基于内存、键值对的非关系型数据库,它的性能十分的优秀,单机节点的Redis无法保证可用性,当单机Redis宕机时,无法继续提供服务
在主从架构 + 哨兵模式下能够使用哨兵监听主节点,当主节点发生宕机时,哨兵监测到挑选出新的主节点进行故障转移,从而保证可用性
本篇文章将围绕哨兵模式,深入浅出的介绍使用哨兵模式、哨兵模式的配置以及哨兵模式的原理
哨兵模式
当主节点宕机后,需要手动把将一台服务器切换为主服务器(人工干预,费时费力),redis2.8开始提供了Sentinel(哨兵)架构来解决这个问题
Redis提供了哨兵的命令,哨兵是一个独立运行的进程,哨兵模式是自动的,不需要我们手动切换,能够后台监控主机是否故障,如果故障了根据投票数自动将从节点转换为主节点
使用哨兵模式
为了方便描述,以下内容的6379实际上说的是占用6379端口号的某个节点
- 配置哨兵配置文件 sentinel.conf
#sentinel monitor <master-name> <ip> <redis-port> <quorum> #quorum 代表如果发生主观下线(单个哨兵认为主机挂了),需要多少个哨兵也认为主机挂了才算客观下线 sentinel monitor myredis 127.0.0.1 6379 1
- 启动哨兵
[root@liang bin]# redis-sentinel liang-config/sentinel.conf 9521:X 04 Apr 2020 17:22:03.559 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 9521:X 04 Apr 2020 17:22:03.559 # Redis version=5.0.8, bits=64, commit=00000000, modified=0, pid=9521, just started 9521:X 04 Apr 2020 17:22:03.559 # Configuration loaded _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 5.0.8 (00000000/0) 64 bit .-`` .-```. ```/ _.,_ ''-._ ( ' , .-` | `, ) Running in sentinel mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 26379 | `-._ `._ / _.-' | PID: 9521 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' 9521:X 04 Apr 2020 17:22:03.560 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. 9521:X 04 Apr 2020 17:22:03.562 # Sentinel ID is c817ed9b9ead4bf0fa429dcf9d7ef04c6dfc7e94 #监控6379主节点 9521:X 04 Apr 2020 17:22:03.562 # +monitor master myredis 127.0.0.1 6379 quorum 1 #6381是6379的从节点 9521:X 04 Apr 2020 17:22:03.563 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379 #6380是6379的从节点 9521:X 04 Apr 2020 17:22:03.565 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
- 从最后几行日志可以看出哨兵监控6379主节点,其中6380、6381是6379的从节点
现在将主节点断开,发生故障转移 - 故障转移
#6379发生故障转移 9521:X 04 Apr 2020 17:23:47.924 # +failover-end master myredis 127.0.0.1 6379 #6380切换为主节点 9521:X 04 Apr 2020 17:23:47.924 # +switch-master myredis 127.0.0.1 6379 127.0.0.1 6380 #6381是6380的从节点 9521:X 04 Apr 2020 17:23:47.924 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6380 #6379是6380的从节点 9521:X 04 Apr 2020 17:23:47.924 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6380
- 发生故障转移后,6380切换为新的主节点,6379、6381切换为从节点
哨兵模式配置
# Example sentinel.conf # 哨兵sentinel实例运行的端口 默认26379 port 26379 # 哨兵sentinel的工作目录 dir /tmp # sentinel monitor <master-name> <ip> <redis-port> <quorum> # 哨兵sentinel监控的redis主节点的 ip port # master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。 # quorum 配置多少个sentinel哨兵统一认为master主节点失联 那么这时客观上认为主节点失联了(客观下线) sentinel monitor mymaster 127.0.0.1 6379 2 # 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供 密码 # 设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码 # sentinel auth-pass <master-name> <password> sentinel auth-pass mymaster MySUPER--secret-0123passw0rd # 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒 # sentinel down-after-milliseconds <master-name> <milliseconds> sentinel down-after-milliseconds mymaster 30000 # 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同步, 这个数字越小,完成failover所需的时间就越长, 但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。 可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。 # sentinel parallel-syncs <master-name> <numslaves> sentinel parallel-syncs mymaster 1 # 故障转移的超时时间 failover-timeout 可以用在以下这些方面: #1. 同一个sentinel对同一个master两次failover之间的间隔时间。 #2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那 里同步数据时。 #3.当想要取消一个正在进行的failover所需要的时间。 #4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时, slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了 # 默认三分钟 sentinel failover-timeout mymaster 180000
哨兵工作原理
哨兵是独立运行用于监控主从节点的,通常为防止单哨兵误判,哨兵常常是以集群的方式来监听节点
哨兵工作原理可以简单分为三个步骤:
- 监控:哨兵通过与节点建立命令、订阅连接来监听节点信息和维护其他哨兵信息
- 通知:当某个哨兵认为某节点主观下线时,通过命令连接告知其他哨兵,判断该节点是否真正下线,当超过一定数量(配置数量)的哨兵认为该节点下线则发生故障转移
- 故障转移:哨兵集群投票挑选出哨兵领导,由哨兵领导来处理故障转移,在从节点中挑选出新的主节点进行主从切换
监控
哨兵会与节点建立命令、订阅连接(发布订阅模式),命令用于向节点发送命令,订阅连接则是节点发布更新状态,订阅它的所有哨兵接收更新数据
哨兵之间通过订阅某节点的连接来感知对方的存在,维持信息状态,因此只会建立命令连接来发送命令
哨兵通过命令连接与节点维持心跳(ping),来感知节点是否下线
哨兵通过节点的订阅连接来维护其他哨兵的信息,当节点收到某个哨兵的命令时会以发布的形式响应回去,哨兵判断响应信息是不是自己的ID,是则说明是自己发的,不是则说明是其他哨兵发的命令,以此来感知其他哨兵的存在和维护其他哨兵信息
通知
当维持心跳期间节点不响应时,哨兵会认为该节点下线(主观下线),从而通过命令连接通知其他哨兵向该节点维持心跳,如果一定数量的哨兵都接收不到该节点的响应则认为该节点发生客观下线
此时会根据raft算法推举在哨兵集群中推举出哨兵领导,来让这个哨兵领导进行故障转移
- raft推举算法:
- 各个节点先进行等待时间的自转,先自转完成后推举自己为领导广播给其他节点
- 其他节点接到后,如果该节点还在自转则会投票给它,如果该哨兵已经推举别的节点了就不会响应
- 收到推举票后如果超过一半数量则成为领导,如果最高票相等则重复步骤1
还不熟悉的同学可以观看动画:raft算法动态展示
故障转移
哨兵领导先根据一些策略过滤从节点,比如:排除掉不在线的从节点、排除响应慢的从节点、排除与旧主节点断开较久的从节点
接着对剩下的从节点列表根据优先级降序、offset(偏移量越大表示数据越新)降序、runid进行排序
排序后挑选出新的主节点,新主节点(此时还是从节点)执行slave no one
与旧主节点断开连接,并让其他从节点执行slaveof ip port
连接新的主节点
总结
本文围绕哨兵模式的可用深入浅出的说明哨兵模式的使用、哨兵配置以及哨兵模式原理
哨兵与节点间建立命令、订阅连接,命令连接用于发送命令、订阅连接用于维护节点信息和感知其他哨兵
哨兵与哨兵之间只建立命令连接,当主观下线时通过命令连接来通知其他哨兵
当发送客观下线时(一定数量哨兵认为某节点下线),哨兵之间根据raft算法推举出哨兵领导处理故障转移
哨兵领导处理故障转移时,先根据某些条件过滤从节点,再根据优先级、offset、runid对过滤后的从节点列表进行排序,最后挑选出新的主节点并进行善后操作(断开旧的主节点,连接新的主节点)
最后
哨兵节点虽然能够保证可用,但是存在节点不能进行水平扩展、推举新的主节点时不能访问Redis等问题,而集群模式既可以进行水平扩展,也能够完成故障转移保证可用,实际中使用集群模式的更多,下篇文章将深入浅出的解析集群模式
- 参考资料
- 《Redis设计与实现》
- 《Redis深度历险》