Redis 哨兵机制
前言
Redis 主从复制模式下,一旦主节点出现了故障不可达,需要人工干预进行故障转移,无论对于 Redis 的应用方还是运维方都带来了很大的不便。对于应用方来说无法及时感知到主节点的变化,必然会造成一定的写数据丢失和读数据错误,甚至可能造成应用方服务不可用。对于 Redis 的运维方来说,整个故障转移的过程是需要人工来介入的,故障转移实时性和准确性上都无法得到保障。Redis 2.8 版本提供哨兵机制,可以解决此类问题。本篇文章介绍哨兵安装部署及原理。
1. 安装部署
1.1 环境介绍
操作系统版本:CentOS Linux release 7.8.2003 (Core)
Redis 版本:Redis server v5.0.12
角色 | IP | 端口 | 说明 |
Master | 172.16.104.57 | 6379 | Redis 主节点 |
slave-1 | 172.16.104.55 | 6379 | slave-1 从节点 |
slave-2 | 172.16.104.56 | 6379 | slave-2 从节点 |
sentinel-1 | 172.16.104.57 | 26379 | sentinel-1 节点 |
sentinel-2 | 172.16.104.55 | 26379 | sentinel-2 节点 |
sentinel-3 | 172.16.104.56 | 26379 | sentinel-3 节点 |
Redis 单机部署参考:Redis 源码安装
1.2 建立复制关系
分别在两个从节点执行下方命令:
slaveof 172.16.104.57 6379
主节点有密码的话,记得配置 masterauth 参数。
查看复制状态 connected_slaves = 2 表示两台从库都在线。
127.0.0.1:6379> info replication # Replication role:master connected_slaves:2 slave0:ip=172.16.104.55,port=6379,state=online,offset=434,lag=1 slave1:ip=172.16.104.56,port=6379,state=online,offset=434,lag=0 master_replid:9898532eb9351f1c4322e01589a344d4632a70e1 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:434 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:434
1.3 部署哨兵节点
1.3.1 编辑配置
编辑 sentinel 节点的配置文件,所有节点都相同,因为是部署在不同的物理机上面。
port 26379 daemonize yes logfile "redis-sentinel-log.log" dir /usr/local/redis/data sentinel monitor mymaster 172.16.104.57 6379 2 sentinel down-after-milliseconds mymaster 10000 sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 180000 sentinel auth-pass mymaster Redis123
PS:配置含义可参考 1.4 哨兵配置说明
1.3.1 启动哨兵
使用 redis-sentinel 命令启动哨兵。
redis-sentinel sentinel-26379.conf
1.3.2 验证
Sentinel 节点本质上是一个特殊的 Redis 节点,可以使用 info 命令查询相关信息。
从下面的片段来看,Sentinel 找到主节点 172.16.104.57
并感知到有两个从节点及三个 Sentinel 节点。
redis-cli -h 127.0.0.1 -p 26379 info Sentinel
1.4 哨兵配置说明
了解 Sentinel 节点的参数的含义,可以帮助更加合理的使用哨兵模式。下面是 1.3.1 使用的配置,将以此为例进行补充说明。
# 端口 port 26379 # 后台启动 daemonize yes # 日志文件名称 logfile "redis-sentinel-log.log" # 工作目录 dir /usr/local/redis/data # 后面将详细说明介绍 sentinel monitor mymaster 172.16.104.57 6379 2 sentinel down-after-milliseconds mymaster 30000 sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 180000 sentinel auth-pass mymaster Redis123
1.4.1 sentinel monitor
sentinel monitor <master-name> <ip> <port> <quorum>
其中 master-name 表示哨兵监控主节点的名称,用于区分多个主节点,用户可自行指定。<ip> 和 <port> 表示需要监控主节点的 ip 和端口 <quorum> 代表要判定主节点最终不可达的票数,一般建议设置为 sentinel 节点数的一半加 1。
从刚才使用的配置文件中发现并没有指定从节点的信息,不是因为不会监控从节点,而是 sentinel 启动后会自动从主节点获取从节点以及其它 sentinel 节点的信息。这点可以从启动后点配置文件中体现。
1.4.2 sentinel down-after-milliseconds
sentinel down-after-milliseconds <master-name> <times>
每个 sentinel 节点都会周期性发生 ping 命令来判断 Redis 节点及 sentinel 节点是否可达,如果超过 down-after-milliseconds 配置的时间且没有有效回复,则判断节点不可达,其中 <times> 单位为毫秒,代表超时时间。
1.4.3 sentinel parallel-syncs
当 Sentinel 节点集合对主节点故障判定达成一致时,Sentinel 领导者节点会做故障转移操作,选出新的主节点,原来的从节点会向新的主节点发起复制操作,parallel-syncs 就是用来限制一次故障转移后,每次向主节点发起复制操作的从节点个数。
如果该参数配置较大,那么意味着故障转移后,将有多个节点同时向主库发起复制操作,尽管不会堵塞主节点正常响应,但是必然会对主节点造成一定的网络和磁盘 IO 开销。
parallel-syncs = 3 表示同时发起复制
parallel-syncs = 1 表示从节点会轮询发起复制
1.4.4 sentinel failover-timeout
sentinel failover-timeout <master-name> <times>
failover-timeout 表示故障转移超时时间。
1.4.5 sentinel auth-pass
sentinel auth-pass <master-name> <password>
主节点如果有设置密码,则也需要写到 sentinel 的配置中。
1.4.6 sentinel notification-script
sentinel notification-script <master-name> <script-path>
故障转移期间,当一些告警级别的 sentinel 事件发生时,会触发 <script-path> 路径下的脚本,并向脚本发送故障参数。
1.4.7 sentinel client-reconfig-script
sentinel client-reconfig-script <master-name> <script-path>
设置通知脚本。
1.5 哨兵 API
1.5.1 调整配置
可以使用 sentinel set 命令调整哨兵的配置,仅对当前节点生效。
sentinel set mymaster quorum 2
1.5.2 展示主节点信息
sentinel masters <master-name>
1.5.3 展示从节点信息
sentinel slaves <master-name>
1.5.4 手动切换
手动对主节点进行故障切换,无需协商,在日常运维中是重要的命令。
sentinel failover <master-name>
1.5.5 检查哨兵是否有效
检测当前可达的 Sentinel 节点总数是否达到 <quorum> 的个数。例如 quorum=3,而当前可达的 Sentinel 节点个数为 2 个,那么将无法进行故障转移,Redis Sentinel 的高可用特性也将失去。
sentinel ckquorum <master-name>
2. 实现原理
2.1 三个定时任务
一套合理的监控机制是 Sentinel 判定节点不可达的重要保证,Redis Sentinel 通过三个定时监控任务完成对各节点的状态监控。
每隔 10 秒,每个 Sentinel 节点会向 Redis 主库和从库发送 info 命令获取最新的拓扑结构。
作用 1:通过执行 info 命令,获取最新的拓扑信息,这也是哨兵不需要主动指定从节点的原因。
作用 2:当有新节点加入时,会快速感知到。
作用 3:节点不可达或者故障转移后,可以通过 info 命令实时更新节点拓扑信息。
每隔 2 秒,每个 Sentinel 节点会向 Redis 数据节点的 sentinel:hello 频道,发送该哨兵节点对于主节点状态的判断信息及当前 Sentinel 节点的信息,同时每个 Sentinel 节点也会通过该频道获取其他节点对主节点的判断。
作用 1:主动发现新的 Sentinel 节点,并与该节点创建连接。
作用 2:与其他哨兵节点交换主库状态,作为客观下线及领导者选举的依据。
每隔 1 秒,每个 Sentinel 节点会向所有 主节点、从节点、Sentinel 节点发送 ping 命令做一次心跳检测,来确认对应节点是否可达,是判断节点是否下线的重要依据。
2.2 主观下线与客观下线
2.2.1 主观下线
从 2.1 可以了解到,每隔 1 秒会向所有节点发送 ping 命令,如果超过 down-after-milliseconds 配置的时间,没有有效回复,Sentinel 节点就会对该节点进行失败判断,这个行为叫做主观下线。主观下线仅表示当前 Sentinel 节点的一家之言,存在误判的可能。
2.2.2 客观下线
当 Sentinel 主观下线的节点是主节点时,该 Sentinel 节点会向其他 Sentinel 节点询问对主节点的判断,当认为主节点下线的 Sentinel 节点个数大于 <quorum> 个数,那么就确认主节点确实已下线,这时该 Sentinel 节点会做出客观下线的决定,这样客观下线的含义是比较明显了,也就是大部分 Sentinel 节点都对主节点的下线做了同意的判定,那么这个判定就是客观的。
2.3 选主机制
2.3.1 哨兵领导者选举
当 Sentinel 节点对 Redis 主节点确认客观下线,此时需要选择一个 Sentinel 节点作为领导者,完成故障转移工作。Redis Sentinel 选主使用的算法是 Raft,算法比较复杂,感兴趣可以看论文 Raft 论文。
2.3.2 故障转移
选举出的领导者 Sentinel 节点将进行 Redis 数据节点故障转移,此时需要对各从节点进行筛选,具体步骤为:
过滤已经主观下线、断线、5 秒内没有回复 Sentinel 节点 ping 响应、与主节点断连时间超过 down-after-milliseconds * 10 秒。
选择 replica-priority 预设从节点优先级列表最高的实例,如果没有则进行下一步。
选择复制偏移量最大的从节点,表示复制的数据最完整,偏移量都相同则进行下一步。
选择 runid 最小的从节点。
Sentinel 节点集合会对原来的主库保持关注,当其恢复正常会命令它复制新的主节点。
后记
2020 年美国科技界纷纷响应 Black Lives Matter,BLM 维权运动,将带有种族色彩的词汇替换。
文章中关于 slave 命令或参数,如果不好使,可以尝试替换为 replica 试试。
参考:
【1】 Redis 官方文档 https://redis.io
【2】《Redis 开发与运维》
【3】《Redis 核心技术与实战》