哨兵模式是redis高可用
的实现方式之一
使用一个或者多个哨兵(Sentinel)实例组成的系统,对redis节点进行监控,在主节点出现故障的情况下,能将从节点中的一个升级为主节点,进行故障转义,保证系统的可用性。
哨兵们是怎么感知整个系统中的所有节点(主节点/从节点/哨兵节点)的
- 首先主节点的信息是配置在哨兵(Sentinel)的配置文件中
- 哨兵节点会和配置的主节点建立起两条连接
命令连接
和订阅连接
- 哨兵会通过
命令连接
每10s发送一次INFO
命令,通过INFO命令
,主节点会返回自己的run_id和自己的从节点信息
- 哨兵会对这些从节点也建立两条连接
命令连接
和订阅连接
- 哨兵通过
命令连接
向从节点发送INFO
命令,获取到他的一些信息
a. run_id
b. role
c. 从服务器的复制偏移量 offset
d. 等 - 因为哨兵对与集群中的其他节点(主从节点)当前都有两条连接,
命令连接
和订阅连接
a. 通过命令连接
向服务器的_sentinel:hello
频道发送一条消息,内容包括自己的ip端口、run_id、配置纪元(后续投票的时候会用到)等
b. 通过订阅连接
对服务器的_sentinel:hello
频道做了监听,所以所有的向该频道发送的哨兵的消息都能被接受到
c. 解析监听到的消息,进行分析提取,就可以知道还有那些别的哨兵服务节点也在监听这些主从节点了,更新结构体将这些哨兵节点记录下来
d. 向观察到的其他的哨兵节点建立命令连接
—-没有订阅连接
哨兵模式下的故障迁移
主观下线
哨兵(Sentinel)节点会每秒一次的频率向建立了命令连接的实例发送PING命令,如果在down-after-milliseconds
毫秒内没有做出有效响应包括(PONG/LOADING/MASTERDOWN)以外的响应,哨兵就会将该实例在本结构体中的状态标记为SRI_S_DOWN
主观下线
客观下线
当一个哨兵节点发现主节点处于主观下线状态时,会向其他的哨兵节点发出询问,该节点是不是已经主观下线了。如果超过配置参数quorum
个节点认为是主观下线时,该哨兵节点就会将自己维护的结构体中该主节点标记为SRI_O_DOWN
客观下线
询问命令SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <run_id>
参数 | 意义 |
---|---|
ip/port | 当前认为下线的主节点的ip和端口 |
current_epoch | 配置纪元 |
run_id | *标识仅用于询问是否下线 有值标识该哨兵节点希望对方将自己设置为leader 询问时用*,选举时用run_id |
leader选举
在认为主节点客观下线
的情况下,哨兵节点节点间会发起一次选举,命令还是上面的命令SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <run_id>
,只是run_id
这次会将自己的run_id
带进去,希望接受者将自己设置为主节点。如果超过半数以上的节点返回将该节点标记为leader的情况下,会有该leader对故障进行迁移
故障迁移
- 在从节点中挑选出新的主节点
a. 通讯正常
b. 优先级排序
c. 优先级相同是选择offset最大的 - 将该节点设置成新的主节点
SLAVEOF no one
,并确保在后续的INGO命令时,该节点返回状态为master - 将其他的从节点设置成从新的主节点复制,
SLAVEOF命令
- 将旧的主节点变成新的主节点的从节点
然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。 各个哨兵之间还会进行监控,这样就形成了多哨兵模式:

优缺点
优点:
哨兵集群,基于主从复制模式,所有的主从配置优点,它全有
主从可以切换,故障可以转移,系统的可用性就会更好
哨兵模式就是主从模式的升级,手动到自动,更加健壮
缺点:
Redis 不便于在线扩容的,集群容量一旦到达上限,在线扩容就十分麻烦
实现哨兵模式的配置很麻烦,里面有很多选项
哨兵模式全部配置
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> <port> <quorum >
sentinel monitor mymaster 127.0.0.1 6379 1
=========================================
当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供密码
设置哨兵sentinel 连接主从的密码,注意必须为主从设置一样的验证密码
sentinel auth-pass
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
============================================
指定多少毫秒之后主节点没有应答哨兵sentinel,哨兵主观上认为主节点下线。默认30秒
sentinel down-after-milliseconds
sentinel down-after-milliseconds mymaster 30000
===============================================
这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。
sentinel parallel-syncs
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
sentinel failover-timeout mymaster 180000
============================================
SCRIPTS EXECUTION
配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
对于脚本的运行结果有以下规则:
若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。
通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,一个是事件的类型,一个是事件的描述。如果sentinel.conf配 置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
sentinel notification-script
sentinel notification-script mymaster /var/redis/notify.sh
========================================================
客户端重新配置主节点参数脚本
当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。
以下参数将会在调用脚本时传给脚本:
目前总是“failover”
是“leader”或者“observer”中的一个
参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的
这个脚本应该是通用的,能被多次调用,不是针对性的。
sentinel client-reconfig-script
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
具体实现
配置哨兵配置文件
[root@localhost qxconfig]# vim sentinel.conf
####sentinel.conf
port 26379
sentinel monitor mymaster 127.0.0.1 6379 1
//保存推出
启动 哨兵 redis-sentinel sentinel.conf
[root@localhost qxconfig]# redis-sentinel sentinel.conf
77498:X 09 Mar 2021 12:18:50.995 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
77498:X 09 Mar 2021 12:18:50.995 # Redis version=6.2.1, bits=64, commit=00000000, modified=0, pid=77498, just started
77498:X 09 Mar 2021 12:18:50.995 # Configuration loaded
77498:X 09 Mar 2021 12:18:50.996 * monotonic clock: POSIX clock_gettime
Redis 6.2.1 (00000000/0) 64 bit
Running in sentinel mode
Port: 26379
PID: 77498
http://redis.io
77498:X 09 Mar 2021 12:18:50.996 # Sentinel ID is cafefa954856b4e6da1e6e851ad23ea772278ea6
77498:X 09 Mar 2021 12:18:50.996 # +monitor master mymaster 127.0.0.1 6379 quorum 1
我来测试一下,开另一个窗口,把主服务的redis 进程杀掉
[root@localhost ~]# ps -ef |grep redis
root 77578 1 0 12:25 ? 00:00:00 redis-server 0.0.0.0:6379
root 77588 74582 0 12:25 pts/0 00:00:00 redis-sentinel *:26379 [sentinel]
root 77639 77598 0 12:27 pts/1 00:00:00 grep --color=auto redis
[root@localhost ~]# kill -9 77578
回到开启哨兵的窗口,可以看到监控的信息,现在已经由于100的主服务器挂了,推举了101服务器。
77588:X 09 Mar 2021 12:25:30.206 # Sentinel ID is cafefa954856b4e6da1e6e851ad23ea772278ea6
77588:X 09 Mar 2021 12:25:30.206 # +monitor master mymaster 127.0.0.1 6379 quorum 1
77588:X 09 Mar 2021 12:28:30.717 * +fix-slave-config slave 192.168.65.102:6379 192.168.65.102 6379 @ mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:28:30.717 * +fix-slave-config slave 192.168.65.101:6379 192.168.65.101 6379 @ mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:19.842 # +sdown master mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:19.842 # +odown master mymaster 127.0.0.1 6379 #quorum 1/1
77588:X 09 Mar 2021 12:30:19.842 # +new-epoch 1
77588:X 09 Mar 2021 12:30:19.842 # +try-failover master mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:19.844 # +vote-for-leader cafefa954856b4e6da1e6e851ad23ea772278ea6 1
77588:X 09 Mar 2021 12:30:19.845 # +elected-leader master mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:19.845 # +failover-state-select-slave master mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:19.946 # +selected-slave slave 192.168.65.101:6379 192.168.65.101 6379 @ mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:19.946 * +failover-state-send-slaveof-noone slave 192.168.65.101:6379 192.168.65.101 6379 @ mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:20.023 * +failover-state-wait-promotion slave 192.168.65.101:6379 192.168.65.101 6379 @ mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:20.716 # +promoted-slave slave 192.168.65.101:6379 192.168.65.101 6379 @ mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:20.716 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:20.774 * +slave-reconf-sent slave 192.168.65.102:6379 192.168.65.102 6379 @ mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:21.753 * +slave-reconf-inprog slave 192.168.65.102:6379 192.168.65.102 6379 @ mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:21.753 * +slave-reconf-done slave 192.168.65.102:6379 192.168.65.102 6379 @ mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:21.813 # +failover-end master mymaster 127.0.0.1 6379
77588:X 09 Mar 2021 12:30:21.813 # +switch-master mymaster 127.0.0.1 6379 192.168.65.101 6379
77588:X 09 Mar 2021 12:30:21.813 * +slave slave 192.168.65.102:6379 192.168.65.102 6379 @ mymaster 192.168.65.101 6379
77588:X 09 Mar 2021 12:30:21.813 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 192.168.65.101 6379
77588:X 09 Mar 2021 12:30:51.851 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 192.168.65.101 6379
有3台服务器 100 ,101 ,102 现在是100被我们干掉了,推举了101,我们来看看
//101服务器变成了主服务器
127.0.0.1:6379> info replication
Replication
role:master
connected_slaves:1
slave0:ip=192.168.65.102,port=6379,state=online,offset=18134,lag=1
master_failover_state:no-failover
master_replid:4f4bd837e0cc51d41f49970821991f4b305f9c89
master_replid2:41b2580c5dd6626869fac1a868aa86793dea92d3
master_repl_offset:18134
second_repl_offset:11994
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:18134
===========================================
127.0.0.1:6379> info replication //102服务器改为101的从服务器
Replication
role:slave
master_host:192.168.65.101
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:18720
slave_priority:100
slave_read_only:1
connected_slaves:0
master_failover_state:no-failover
master_replid:4f4bd837e0cc51d41f49970821991f4b305f9c89
master_replid2:41b2580c5dd6626869fac1a868aa86793dea92d3
master_repl_offset:18720
second_repl_offset:11994
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:18720
之后,我们再恢复100的redis ,发现自动变成了从服务器。
[root@localhost local]# redis-server bin/qxconfig/redis.conf
[root@localhost local]# redis-cli
127.0.0.1:6379> info replication
Replication
role:slave
master_host:192.168.65.101
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:49075
slave_priority:100
slave_read_only:1
connected_slaves:0
master_failover_state:no-failover
master_replid:4f4bd837e0cc51d41f49970821991f4b305f9c89
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:49075
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:43664
repl_backlog_histlen:5412