基本概念
主从复制的机制是其他高可用方式的基础,下面介绍的哨兵方式和集群方式都依赖于主从复制机制
若干 Sentinel 节点组成的分布式集群,可以实现故障发现、故障自动转移、配置中心和客户端通知
节点数量要满足 2n+1(n>=1)的奇数个
哨兵节点: 哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的 Redis 节点,不存储数据
数据节点: 主节点和从节点都是数据节点
哨兵方式在主从复制的基础上,实现了故障自动切换的功能
:
监控
: 哨兵会不断地检查主节点和从节点是否运作正常(发布-订阅
)自动故障转移
:当主节点不能正常工作时,哨兵会开始 自动故障转移操作
它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点
配置提供者
: 客户端在初始化时,通过连接哨兵来获得当前 Redis 服务的主节点地址通知
:哨兵可以将故障转移的结果发送给客户端
配置及使用
以
一主二从三哨兵
的架构来搭建一个哨兵系统
数据节点
找到
redis.conf
文件复制三份: redis-master.conf、redis-slave1.conf、redis-slave2.conf
# redis-master.conf master
port 6380
daemonize yes
logfile "6380.log"
dbfilename "dump-6380.rdb"
# redis-slave1.conf slave-1
port 6381
daemonize yes
logfile "6381.log"
dbfilename "dump-6381.rdb"
slaveof 127.0.0.1 6380
# redis-slave2.conf slave-2
port 6382
daemonize yes
logfile "6382.log"
dbfilename "dump-6382.rdb"
slaveof 127.0.0.1 6380
####################################################################################
# 启动三个 redis 实例
/usr/local/redis/bin/redis-server redis-master.conf
/usr/local/redis/bin/redis-server redis-slave1.conf
/usr/local/redis/bin/redis-server redis-slave2.conf
####################################################################################
# 查看redis进程
ps -aux | grep redis
####################################################################################
# 连接主节点,查看状态(info Replication)
redis -h 127.0.0.1 -p 6380
哨兵节点
哨兵节点本质上是特殊的 Redis 节点,所以配置几乎没什么差别,只是在端口上做区分
# redis-sentinel-1.conf
port 16380
daemonize yes
logfile "16380.log"
sentinel monitor redis-master 127.0.0.1 6380 2
# redis-sentinel-2.conf
port 16381
daemonize yes
logfile "16381.log"
sentinel monitor redis-master 127.0.0.1 6380 2
# redis-sentinel-3.conf
port 16382
daemonize yes
logfile "16382.log"
sentinel monitor redismaster 127.0.0.1 6380 2
####################################################################################
# 启动哨兵节点
/usr/local/redis/bin/redis-server redis-sentinel-1.conf --sentinel
/usr/local/redis/bin/redis-server redis-sentinel-2.conf --sentinel
/usr/local/redis/bin/redis-server redis-sentinel-3.conf --sentinel
####################################################################################
# 登录哨兵节点,查看状态(info Sentinel)
redis -h 127.0.0.1 -p 16380
sentinel monitor redis-master 127.0.0.1 6380 2
该哨兵节点监控
127.0.0.1:63780
这个主节点,该主节点的名称是redis-master
`2` :主节点的故障判定有关,至少需要 `2` 个哨兵节点同意,才能判定主节点故障并进行故障转移
Python连接
from redis import Sentinel
sentinel = Sentinel(
[('127.0.0.1', 16380), ('127.0.0.1', 16381), ('127.0.0.1', 16382)],
socket_timeout=0.5
)
# 获取主服务器地址,discover_master 参数为自己的mastername
master = sentinel.discover_master('redis-master')
print(master)
Sentinel命令
# 展示所有被监控的主节点状态以及相关的统计信息
sentinel masters
# 展示指定<master name>的主节点状态以及相关的统计信息
sentinel master <master name>
# 展示指定<master name>的从节点状态以及相关的统计信息
sentinel slaves <master name>
# 展示指定<master name>的Sentinel节点集合(不包含当前Sentinel节点)
sentinel sentinels <master name>
# 返回指定<master name>主节点的IP地址和端口
sentinel get-master-addr-by-name <master name>
# 对指定<master name>主节点进行强制故障转移
sentinel failover <master name>
# 检测当前可达的Sentinel节点总数是否达到<quorum>的个数
sentinel ckquorum <master name>
# 取消当前Sentinel节点对于指定<master name>主节点的监控
sentinel remove <master name>
# 通过命令的形式来完成Sentinel节点对主节点的监控
sentinel monitor <master name> <ip> <port> <quorum>
# 动态修改Sentinel节点配置选项
sentinel set <master name>
# Sentinel节点之间用来交换对主节点是否下线的判断
# 根据参数的不同,还可以作为Sentinel领导者选举的通信方式
sentinel is-master-down-by-addr
流程及原理
定时监控
每隔 10 秒,每个 Sentinel 节点会向主节点和从节点发送 info 命令获取 Redis 数据节点的信息
这也是为什么 Sentinel 节点不需要显式配置监控从节点
当有新的从节点加入时都可以立刻感知出来
节点不可达或者故障转移后,可以通过 info 命令实时更新节点拓扑信息
每隔 2 秒,每个 Sentinel 节点会向 Redis 数据节点的
__sentinel__:hello
频道上发送该 Sentinel 节点对于主节点的判断以及当前 Sentinel 节点的信息,同时每个 Sentinel 节点也会订阅
该频道,来了解其他Sentinel 节点以及它们对主节点的判断消息格式
s_ip:sentinel的ip
s_port:sentinel的端口
s_runid:sentinel云心id
s_epoch:sentinel当前的配置纪元
m_name:主服务器名字
m_ip:主服务器ip
m_port:主服务器端口
m_epoch:主服务器纪元
发现新的 Sentinel 节点
通过订阅主节点的
__sentinel__:hello
了解其他的 Sentinel 节点信息如果是新加入的 Sentinel 节点,将该 Sentinel 节点信息保存起来(sentinelRedisInstance)
并与该 Sentinel 节点创建连接
- Sentinel 节点之间交换主节点的状态,作为后面客观下线以及领导者选举的依据 - 每隔 1 秒,每个 Sentinel 节点会向主节点、从节点、其余 Sentinel 节点发送一条 ping 命令做一次心跳检测,来确认这些节点当前是否可达
主观/客观下线
主观下线
单个 sentinel 认为某个服务下线(有可能是接收不到订阅,之间的网络不通等等原因)
sentinel 会以每秒一次的频率向所有与其建立了命令连接的实例(master、slave、其他 sentinel)发 ping 命令
通过判断 ping 回复是有效回复还是无效回复,来判断实例是否在线(对该 sentinel 来说是主观在线
)
sentinel 配置文件中的
down-after-milliseconds
设置了判断主观下线的时间长度
如果实例在 down-after-milliseconds 毫秒内返回的都是无效回复,那么 sentinel 会认为该实例已下线(主观)
并修改其 flags 状态为 SRI_S_DOWN
在实际的工作当中,多个 sentinel 配置的 down-after-milliseconds 超时时间推荐一致
客观下线
只针对主节点
,从节点和哨兵节点不需要这一步
当 Sentinel 主观下线的节点是主节点时:
该 Sentinel 节点会通过 sentinel ismaster-down-by-addr 命令向其他 Sentinel 节点询问对主节点的判断
当超过配置中的
<quorum>
个数,Sentinel 节点认为主节点确实有问题这时该 Sentinel 节点会做出客观下线的决定,并后续对其做故障转移操作
如果每个 Sentinel 配置的 down-after-milliseconds 时间不一致,会很难超过<quorum>
配置的个数
sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid>
eg:
sentinel is-master-down-by-addr 127.0.0.1 6379 0 *
ip:主节点 IP
port:主节点端口
current_epoch:当前配置纪元
runid:此参数有两种类型,当 runid为
*
:Sentinel 节点直接交换对主节点下线的判定
在领导者Sentinel 节点选举时,runid 等于当前 Sentinel 节点的 runid
作用是当前 Sentinel 节点,希望目标 Sentinel 节点同意自己成为领导者的请求
一个 sentinel 接收另一个 sentinel 发来的 is-master-down-by-addr 后
提取参数,根据 ip 和端口,检测该服务时候在该 sentinel 主观下线,并且回复 is-master-down-by-addr
down_state:目标 Sentinel 节点对于主节点的下线判断,1 是下线,0 是在线
leader_runid:
*
:代表返回结果是用来做主节点是否不可达具体的 runid
:代表目标节点同意 runid 成为领导者
leader_epoch:领导者纪元
领导者 Sentinel 选举
Redis 使用了 Raft 算法实现领导者选举,大体思路:
每个在线的 Sentinel 节点都有资格成为领导者,每个 Sentinel 节点发现当它确认主节点客观下线检查时候,会向其他 Sentinel 节点发送 sentinel is-master-down-by-addr 命令,要求将自己设置为领导者
每个节点在每个选举轮次中只有一次投票权,收到命令的 Sentinel 节点,如果没有同意过其他 Sentinel 节点的 sentinelis-master-down-by-addr 命令,将同意该请求,否则拒绝
如果该 Sentinel 节点发现自己的票数已经大于等于 max(quorum,num(sentinels)/2+1),那么它将成为领导者。其他的投票就会终止,即使后续还有其他的哨兵节点到达配置,也没有作用
如果此过程没有选举出领导者, 暂定一段时间,再进行下一轮选举,current_epoch 加 1
选举流程
s1 (哨兵节点) 节点首先完成客观下线的检查,然后向 s2 和 s3 发送成为领导者的请求
s2 节点完成客观下线的检查,然后向 s1 和 s3 发送成为领导者的请求
s3节点完成客观下线的检查,然后向 s1和 s2发送成为领导者的请求
故障转移
在从节点列表中选出一个作为新的主节点
过滤
“不健康”节点(主观下线、断线)
5 秒内没有回复过 Sentinel 节点 ping 响应
与主节点失联超过 down-after-milliseconds*10s(断线时间越长主从数据不一致问题越严重)
选择 slave-priority(从节点优先级)最高的从节点列表,如果存在则返回,不存在则继续
如果优先级一样,选择
复制偏移量最大的从节点
(复制的最完整),如果存在则返回,不存在则继续如果偏移量一样,选择 runid 最小的从节点
挑选从节点的重要原则:
在从节点列表中挑选与主节点数据最一致的节点
Sentinel 领导者节点会对第一步选出来的从节点执行 slaveof no one 命令让其成为主节点
Sentinel 领导者节点会向剩余的从节点发送命令,让它们成为新主节点的从节点,复制规则和 parallel-syncs 参数有关:slaveof ip port
Sentinel 节点集合会将原来的主节点更新为从节点,并保持着对其关注,当其恢复后命令它去复制新的主节点
优点
在Redis主从复制的基础上,
增加了故障自动转移
方便实现 Redis 数据节点的线形扩展
突破 Redis 自身单线程瓶颈,可较大程度上满足Redis 大容量或高性能的业务需求
可以实现一套 Sentinel 监控一组 Redis 数据节点或多组数据节点
缺点
部署相对 Redis 主从模式要复杂一些,原理理解更繁琐
资源浪费,Redis 数据节点中
slave 节点作为备份节点不提供服务
Redis Sentinel 主要是
针对主节点的高可用切换
:主观下线(并不执行故障转移)
客观下线
不能解决读写分离问题,实现起来相对复杂
全部配置
# Example sentinel.conf
# 哨兵sentinel实例运行的端口 默认26379
port 26379
# 哨兵sentinel的工作目录
dir /tmp
# 哨兵sentinel监控的redis主节点的 ip port
# master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。
# quorum 配置多少个sentinel哨兵统一认为master主节点失联 那么这时客观上认为主节点失联了
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
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 <master-name> <milliseconds>
sentinel failover-timeout mymaster 180000
# SCRIPTS EXECUTION
# 配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
# 对于脚本的运行结果有以下规则:
# 若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
# 若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
# 如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
# 一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。
# 通知型脚本: 当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,一个是事件的类型,一个是事件的描述。如果sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
# 通知脚本
# shell编程
# sentinel notification-script <master-name> <script-path>
sentinel notification-script mymaster /var/redis/notify.sh
# 客户端重新配置主节点参数脚本
# 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。
# 以下参数将会在调用脚本时传给脚本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# 目前<state>总是“failover”,
# <role>是“leader”或者“observer”中的一个。
# 参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的
# 这个脚本应该是通用的,能被多次调用,不是针对性的。
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
参考:
评论区