Redis哨兵机制RedisSentinel

哨兵机制RedisSentinel

主从复制时,我们是手动切换主从库实在是太麻烦了。别担心,Redis 的哨兵功能就是为了这个而生的。
哨兵 Redis Sentinel
哨兵就是帮我们实现主从库自动切换的功能。当主库发生问题,无法访问时,哨兵会马上检测到,并排除网络问题在一定时间后确认主库确实是挂了,这时,就会将某一台从库设置为新的主库,其它的从库也自动配置连接到这台新的主库上。
而当原来老的主库恢复访问后,哨兵会将它重新加入到集群中,但是,这个老的主库只能成为一台从库了。(新王登基,旧王称臣)。

怎么配置呢?你可以先在你的配置文件目录看看有没有一个叫做 redis-sentinel.conf 的文件,这个文件就是哨兵的配置文件。

接下来我们直接运行它,使用 redis-server 就可以,只是要加个 --sentinel 参数。

➜  redis-server redis-sentinel.conf --sentinel
………………
48882:X 22 Jun 2022 10:06:06.458 # +monitor master mymaster 127.0.0.1 6379 quorum 1
48882:X 22 Jun 2022 10:06:06.459 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
48882:X 22 Jun 2022 10:06:06.460 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379

如果没有,只需要创建一个配置文件redis-sentinel.conf ,然后有下面这一行配置就行了。

sentinel monitor mymaster 127.0.0.1 6379 1

它的意思是 :

sentinel monitor <哨兵集群名字> <监控的主库IP> <监控的主库端口> <选举主库时的需要几个哨兵同意>

示例中,哨兵名字就是 mymaster ,监控的是 6379 这个库,只需要1个哨兵同意就可以切换主库。

最后这个参数的具体意思我们后面再说。

➜  redis-server redis-sentinel.conf --sentinel
………………
48882:X 22 Jun 2022 10:06:06.458 # +monitor master mymaster 127.0.0.1 6379 quorum 1
48882:X 22 Jun 2022 10:06:06.459 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
48882:X 22 Jun 2022 10:06:06.460 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379

看到上面的输出之后,你的哨兵服务就已经正常启动了。

除了 redis-server 命令外,使用 redis-sentinel 命令也可以启动哨兵实例。

接下来我们就直接可以进行测试了,先关闭主库,

我的电脑是 Mac下的brew安装的redis ,自动运行的6379,所以我也用 brew 去关闭。

// 关闭 6379
➜  brew services stop redis
Stopping `redis`... (might take a while)
==> Successfully stopped `redis` (label: homebrew.mxcl.redis)

接下来我们就要看看 6380、6381 和哨兵实例都产生了什么变化。

如果你是直接运行,没有后台运行的话,就可以明显的看到这三个服务实例在输出内容。

// 6380
………………………………
4449:S 24 Jun 2022 11:37:42.652 * Connecting to MASTER 127.0.0.1:6379
4449:S 24 Jun 2022 11:37:42.653 * MASTER <-> REPLICA sync started
4449:S 24 Jun 2022 11:37:42.653 # Error condition on socket for SYNC: Connection refused
4449:S 24 Jun 2022 11:37:42.919 * Connecting to MASTER 127.0.0.1:6381
4449:S 24 Jun 2022 11:37:42.919 * MASTER <-> REPLICA sync started
4449:S 24 Jun 2022 11:37:42.919 * REPLICAOF 127.0.0.1:6381 enabled (user request from 'id=5 addr=127.0.0.1:61954 laddr=127.0.0.1:6380 fd=9 name=sentinel-295debd7-cmd age=102 idle=0 flags=x db=0 sub=0 psub=0 multi=4 qbuf=329 qbuf-free=44721 argv-mem=4 obl=45 oll=0 omem=0 tot-mem=62500 events=r cmd=exec user=default redir=-1')
4449:S 24 Jun 2022 11:37:42.921 # CONFIG REWRITE executed with success.
4449:S 24 Jun 2022 11:37:42.921 * Non blocking connect for SYNC fired the event.
4449:S 24 Jun 2022 11:37:42.921 * Master replied to PING, replication can continue...
4449:S 24 Jun 2022 11:37:42.921 * Trying a partial resynchronization (request bacd481115f145bc151206de41a6d2f7d5b7f408:5346).
4449:S 24 Jun 2022 11:37:42.921 * Successful partial resynchronization with master.
4449:S 24 Jun 2022 11:37:42.921 # Master replication ID changed to b0b5a4d75d8ec37f3d12f83dc58db6713007446b
4449:S 24 Jun 2022 11:37:42.921 * MASTER <-> REPLICA sync: Master accepted a Partial Resynchronization.

// 6381
……………………
4447:S 24 Jun 2022 11:37:42.824 * Connecting to MASTER 127.0.0.1:6379
4447:S 24 Jun 2022 11:37:42.825 * MASTER <-> REPLICA sync started
4447:S 24 Jun 2022 11:37:42.825 # Error condition on socket for SYNC: Connection refused
4447:M 24 Jun 2022 11:37:42.860 * Discarding previously cached master state.
4447:M 24 Jun 2022 11:37:42.860 # Setting secondary replication ID to bacd481115f145bc151206de41a6d2f7d5b7f408, valid up to offset: 5346. New replication ID is b0b5a4d75d8ec37f3d12f83dc58db6713007446b
4447:M 24 Jun 2022 11:37:42.860 * MASTER MODE enabled (user request from 'id=7 addr=127.0.0.1:61952 laddr=127.0.0.1:6381 fd=9 name=sentinel-295debd7-cmd age=102 idle=0 flags=x db=0 sub=0 psub=0 multi=4 qbuf=202 qbuf-free=44848 argv-mem=4 obl=45 oll=0 omem=0 tot-mem=62500 events=r cmd=exec user=default redir=-1')
4447:M 24 Jun 2022 11:37:42.862 # CONFIG REWRITE executed with success.
4447:M 24 Jun 2022 11:37:42.921 * Replica 127.0.0.1:6380 asks for synchronization
4447:M 24 Jun 2022 11:37:42.921 * Partial resynchronization request from 127.0.0.1:6380 accepted. Sending 156 bytes of backlog starting from offset 5346.

// 哨兵 26379
…………………………
4456:X 24 Jun 2022 11:37:42.698 # +sdown master mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:42.698 # +odown master mymaster 127.0.0.1 6379 #quorum 1/1
4456:X 24 Jun 2022 11:37:42.698 # +new-epoch 1
4456:X 24 Jun 2022 11:37:42.699 # +try-failover master mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:42.701 # +vote-for-leader 295debd78028b566248887589442ee31cae931d5 1
4456:X 24 Jun 2022 11:37:42.701 # +elected-leader master mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:42.701 # +failover-state-select-slave master mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:42.792 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:42.792 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:42.859 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:42.863 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:42.863 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:42.918 * +slave-reconf-sent slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:43.917 * +slave-reconf-inprog slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:43.917 * +slave-reconf-done slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:44.018 # +failover-end master mymaster 127.0.0.1 6379
4456:X 24 Jun 2022 11:37:44.018 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6381
4456:X 24 Jun 2022 11:37:44.018 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6381

从上面的输出可以看到。
6380 会不停的输出 Error condition on socket for SYNC: Connection refused ,在哨兵切换之后, 紧接着会输出 Connecting to MASTER 127.0.0.1:6381 ,这就明显看出来了,现在主库变成了 6381 ,6380 依然还是从库,只是换了主库
6381 同样也是先不停的输出连不上 6379 了,接着就和 6380 不同了,它会多出一个 MASTER MODE enable … 相关的内容,也就是开启主库模式了
26379 是默认的哨兵的端口,它也发现6379挂了,现在就开始进行故障切换:
failover-state-select-slave… 表示要从之前主库的从库中找一个新的主库
selected-slave… 说明这个6381合适
failover-state-send-slaveof-noone 是向新的主库发送指令,这个指令就是 SLAVEOF no one ,也就是把自己转成主库
promoted-slave… 表示所有的哨兵确认6381已经变成主库了
failover-state-reconf-slaves… 表示开始发送配置信息进行切换,也就是从库执行 SLAVEOF 127.0.0.1 6381
failover-end 表明切换完成
switch-master 就是说切换完成了,哨兵也开始监控新的主库
好了,现在来验证一下吧。进入6381看看 ROLE 命令有什么变化。

// 6381
127.0.0.1:6381> role
1) "master"
2) (integer) 13801
3) 1) 1) "127.0.0.1"
      2) "6380"
      3) "13668"

接下来我们重启 6379 。

// 重启 6379
➜  brew services start redis
==> Successfully started `redis` (label: homebrew.mxcl.redis)
// 6381
127.0.0.1:6381> role
1) "master"
2) (integer) 30932
3) 1) 1) "127.0.0.1"
      2) "6380"
      3) "30799"
   2) 1) "127.0.0.1"
      2) "6379"
      3) "30799"

哨兵实例也是可以通过 redis-cli 连接的,所以上面的 getMasterAddrByName() 也是一个 Redis 中的命令。

➜ redis-cli -p 26379
127.0.0.1:26379> SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6379"

多哨兵选举
多哨兵选举。这个内容呀,如果做过分布式开发的同学应该不会陌生。就是说对于一个服务来说,当它的主机挂了,如果需要确定由哪个从机来顶替主机的位置话,往往会通过多个监控服务进行选举投票产生结果。而且,大部分程序都会要求监控程序是单数,比如 3、5、7 个监控程序,因为如果是偶数的话,可能会出现选举结果票数相同的问题。

对于 Redis 中的哨兵来说,也是支持这种监控形式的。那么就有人要问了,为啥呀?还不是为了高可用和性能最佳化。
咱们先来看看怎么配置。先把 redis-sentinel.conf 中的配置修改下,改成需要 2 台哨兵同意才能进行切换。

sentinel monitor mymaster 127.0.0.1 6379 2

然后第一步就是增加配置文件,和多个Redis实例一起运行一样,哨兵也可以通过修改端口号进行多个实例同时运行。第二步就是一个一个的启动起来。

➜  vim redis-sentinel_80.conf
include /usr/local/etc/redis-sentinel.conf
port 26380
pidfile "/var/run/redis-sentinel_80.pid"

➜  vim redis-sentinel_81.conf
include /usr/local/etc/redis-sentinel.conf
port 26381
pidfile "/var/run/redis-sentinel_81.pid"

➜  redis-sentinel redis-sentinel_80.conf
➜  redis-sentinel redis-sentinel_81.conf
➜  redis-sentinel redis-sentinel.conf

注意看我上面的启动顺序,如果反了可是有问题的哦。如果先运行 26379 的主配置文件,那么其它两个新的哨兵是加不进来的。为什么呢?因为哨兵在启动后就会往它们自己的配置文件中写入一些数据,在这其中有个 myid 是用于标识当前这台哨兵的id信息的。上面的配置文件我们都是使用include去复用26379 的配置文件的,如果先启动26379 ,就会生成 26379的myid ,另外两台一看有myid了,也就不会生成自己的了(仅限单机测试共用配置文件的情况下)。因此,在整个哨兵集群中还是只会看到一台哨兵服务器。

➜  vim redis-sentinel_80.conf
include /usr/local/etc/redis-sentinel.conf
port 26380
pidfile "/var/run/redis-sentinel_80.pid"

Generated by CONFIG REWRITE

protected-mode no
user default on nopass sanitize-payload ~* &* +@all
dir "/private/tmp"
sentinel myid 03fbd63817310971644e879bd35bf5317b9ec726
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel config-epoch mymaster 4
sentinel leader-epoch mymaster 4
sentinel known-replica mymaster 127.0.0.1 6380
sentinel known-replica mymaster 127.0.0.1 6381
sentinel current-epoch 4
sentinel known-sentinel mymaster 127.0.0.1 26379 db7998b0415376b03b3b1daddf9192a1ab03db6c
sentinel known-sentinel mymaster 127.0.0.1 26381 07aefcb93ac7a6df48820873abb67d5c80e7a9e2

下次重启哨兵的时候,最好把所有哨兵的配置文件中的 # Generated by CONFIG REWRITE 以下的内容全部删掉。最后一台哨兵启动起来之后,你可以看看三台哨兵输出的内容,都可以看到下面这些东西。

5495:X 24 Jun 2022 14:22:44.506 # Sentinel ID is 4b45c338f5195b97bda8fec95d027ded95063a36
5495:X 24 Jun 2022 14:22:45.451 * +sentinel sentinel 8b0cb442c190569b7a257bc62cad99b782511a45 127.0.0.1 26380 @ mymaster 127.0.0.1 6379
5495:X 24 Jun 2022 14:22:46.396 * +sentinel sentinel 273bd99ab214d8daaafbd6dd3822e851ef7a218e 127.0.0.1 26381 @ mymaster 127.0.0.1 6379

注意看,三台哨兵之间已经建立起连接了,不需要我们去设置什么 SLAVEOF 之类的命令。然后它们的 myid都不相同,现在这种情况下哨兵集群就搭建完成了。

然后你就可以测试一下了,先停掉主库,看看切换正常不正常,如果不出意外,应该是能正常切换的。然后恢复主库,接下来停掉两台哨兵,再停掉主库,看看还能不能自动切换。
切换流程与通信
相信上面的配置大家都没问题,接下来就是真正的进阶部分了,整个哨兵的切换流程是怎么样的呢?其实官方文档已经写得很详细了,咱们就再简单概括一下。

每个哨兵以每秒钟一次的频率向它已配置的主库发送 PING命令,这就是心跳检测
如果一个实例的PING回复时间超了 redis-sentinel.conf 中 down-after-milliseconds指定的值,那么这个实例就会被标记为主观下线
当主库被标记为主观下线之后,那么所有的哨兵会继续按秒确认它是不是真的下线了,如果只有一台哨兵就不存在这个情况啦,在有多个哨兵的情况下,当所有哨兵都确认之后,它就会转换一个状态,被标记为客观下线
本来正常情况下,哨兵会每 10 秒向主从库发送 info 命令,但当出现客观下线的主库后,会变成1秒一次
最后,多数哨兵通过之后,执行切换流程,就是上面我们看到哨兵的日志中输出的流程
现在还有一个问题,主从配置的时候,我们需要通过 SLAVEOF来确定主从,但为啥多台哨兵就直接可以互相通信了呢?
其实呀,多台哨兵监控的都是同一个主库,在这种情况下,哨兵会默认每两秒向主库发送 sentinel:hello 命令,并携带自己的信息,就是 IP 地址、端口、runid(myid)这些信息。主库也会返回所有监控它的哨兵的信息,这样一台哨兵也就知道了还有别的领导在盯着主库,于是,哨兵和哨兵之间也建立起了联系。其实,这就是应用我们之前讲过的 Pub/Sub 机制来实现的,大家都订阅同一个哨兵频道了(sentinel:hello)。同时,哨兵也会修改自己的配置信息,也就是我们前面说的,配置文件中生成的那些内容,会加上别的哨兵的信息。因此,哨兵在重启的时候,特别是某台哨兵修改了配置文件的时候,一定要去清理配置文件中之前生成的那些信息。

总结
配置、原理其实都不难理解,就是心跳检测有问题了就向别的从库发送命令实现自动切换。
但是真正的源码实现可不是我这种水平的可以分析出来的,而且大部分的面试中,能说出哨兵怎么配,需要注意什么,大概的流程是怎样的,就已经能吊打不少同行了。

关注:分布式系统中部署Redis ,就解决了主从和哨兵自动切换的问题。

也就是说,一套 Redis Cluster分布式集群架构,就是自带主从、哨兵以及分布式部署能力的。

参考文档:https://redis.io/docs/manual/sentinel/

转载:https://mp.weixin.qq.com/s/pKm0x8qsZTSTd_teWIpPkw

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值