Redis 中的哨兵
# 130.Redis 中的哨兵
Redis 提供了哨兵工具来实现自动化的系统监控和故障恢复功能,本文简单介绍下哨兵
# 什么是哨兵
顾名思义,哨兵的作用就是监控 Redis 系统的运行状况。它的功能包括以下两个。
(1)监控主数据库和从数据库是否正常运行。
(2)主数据库出现故障时自动将从数据库转换为主数据库。
哨兵是一个独立的进程,使用哨兵的一个典型架构如图 8-3 所示。
图 8-3 一个典型的使用哨兵的 Redis 架构。虚线表示主从复制关系,实线表示哨兵的监控路径
在一个一主多从的 Redis 系统中,可以使用多个哨兵进行监控任务以保证系统足够稳健,如图所示。注意,此时不仅哨兵会同时监控主数据库和从数据库,哨兵之间也会互相监控。
# 马上上手
我们首先实际使用一下哨兵,来了解哨兵是如何工作的。为了简单期间,我们搭建一个主数据库和两个从数据库。主数据库的端口为 6379,两个从数据库的端口分别为 6380 和 6381。
# 一主二从
我们使用 Redis 命令行客户端来获取复制状态,以保证复制配置正确。首先是主数据库:
redis 6379> INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=10125,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=10125,lag=1
2
3
4
5
6
可见其连接了两个从数据库,配置正确。然后用同样的方法查看两个从数据库的配置:
redis 6380> INFO replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
redis 6381> INFO replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
2
3
4
5
6
7
8
9
10
11
当出现的信息如上时,即证明一主二从的复制配置已经成功了。
# 配置哨兵
接下来开始配置哨兵。建立一个配置文件,如 sentinel.conf,内容为:
sentinel monitor mymaster 127.0.0.1 6379 1
其中 mymaster 表示要监控的主数据库的名字,可以自己定义一个。这个名字必须仅由大小写字母、数字和“.-_”这 3 个字符组成。后两个参数表示主数据库的地址和端口号,这里我们要监控的是主数据库 6379。最后的 1 表示最低通过票数,后面会介绍。
接下来执行来启动 Sentinel 进程,并将上述配置文件的路径传递给哨兵:
$ redis-sentinel /path/to/sentinel.conf
需要注意的是,配置哨兵监控一个系统时,只需要配置其监控主数据库即可,哨兵会自动发现所有复制该主数据库的从数据库。启动哨兵后,哨兵输出如下内容:
[71835] 19 Feb 22:32:28.730 # Sentinel runid is
e3290844c1a404699479771846b716c7fc830e80
[71835] 19 Feb 22:32:28.730 # +monitor master mymaster 127.0.0.1 6379 quorum 1
[71835] 19 Feb 22:33:09.997 *+slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaste@127.0.0.1 6379
[71835] 19 Feb 22:33:30.068 *+slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster
127.0.0.1 6379
2
3
4
5
6
其中+slave 表示新发现了从数据库,可见哨兵成功地发现了两个从数据库。现在哨兵已经在监控这 3 个 Redis 实例了
# 关闭主数据库
这时我们将主数据库(即运行在 6379 端口上的 Redis 实例)关闭(杀死进程或使用 SHUTDOWN 命令),等待指定时间后(默认为 30 秒,可以配置),哨兵会输出如下内容:
[71835] 19 Feb 22:36:03.780 # +sdown master mymaster 127.0.0.1 6379
[71835] 19 Feb 22:36:03.780 # +odown master mymaster 127.0.0.1 6379 #quorum 1/1
2
其中+sdown 表示哨兵主观认为主数据库停止服务了,而+odown 则表示哨兵客观认为主数据库停止服务了,关于主观和客观的区别后文会详细介绍。
此时哨兵开始执行故障恢复,即挑选一个从数据库,将其升格为主数据库。输出内容如下:
[71835] 19 Feb 22:36:03.780 # +try-failover master mymaster 127.0.0.1 6379
……
[71835] 19 Feb 22:36:05.913 # +failover-end master mymaster 127.0.0.1 6379
[71835] 19 Feb 22:36:05.913 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
[71835] 19 Feb 22:36:05.914 *+slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster
127.0.0.1 6380
[71835] 19 Feb 22:36:05.914 *+slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster
127.0.0.1 6380
2
3
4
5
6
7
8
+try-failover 表示哨兵开始进行故障恢复,+failover-end 表示哨兵完成故障恢复,期间涉及的内容比较复杂,包括领头哨兵的选举、备选从数据库的选择等,放到后面介绍,此处只需要关注最后 3 条输出。+switch-master 表示主数据库从 6379 端口迁移到 6380 端口,即 6380 端口的从数据库被升格为主数据库,同时两个+slave 则列出了新的主数据库的两个从数据库,端口分别为 6381 和 6379。其中 6379 就是之前停止服务的主数据库,可见哨兵并没有彻底清除停止服务的实例的信息,这是因为停止服务的实例有可能会在之后的某个时间恢复服务,这时哨兵会让其重新加入进来,所以当实例停止服务后,哨兵会更新该实例的信息,使得当其重新加入后可以按照当前信息继续对外提供服务。
此例中 6379 端口的主数据库实例停止服务了,而 6380 端口的从数据库已经升格为主数据库,当 6379 端口的实例恢复服务后,会转变为 6380 端口实例的从数据库来运行,所以哨兵将 6379 端口实例的信息修改成了 6380 端口实例的从数据库。
故障恢复完成后,可以使用 Redis 命令行客户端重新检查 6380 和 6381 两个端口上的实例的复制信息:
redis 6380> INFO replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=270651,lag=1
redis 6381> INFO replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
2
3
4
5
6
7
8
9
10
11
可以看到 6380 端口上的实例已经确实升格为主数据库了,同时 6381 端口上的实例是其从数据库。整个故障恢复过程就此完成。
# 启动旧的主数据库
那么此时我们将 6379 端口上的实例重新启动,会发生什么情况呢?首先哨兵会监控到这一变化,并输出:
[71835] 19 Feb 23:46:14.573 # -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster
127.0.0.1 6380
[71835] 19 Feb 23:46:24.504 *+convert-to-slave slave 127.0.0.1:6379 127.0.0.1 6379
@ mymaster 127.0.0.1 6380
2
3
4
-sdown 表示实例 6379 已经恢复服务了(与+sdown 相反),同时+convert-to-slave 表示将 6379 端口的实例设置为 6380 端口实例的从数据库。
这时使用 Redis 命令行客户端查看 6379 端口实例的复制信息为:
redis 6379> INFO replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
2
3
4
5
同时 6380 端口实例的复制信息为:
redis 6380> INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=292948,lag=1
slave1:ip=127.0.0.1,port=6379,state=online,offset=292948,lag=1
2
3
4
5
6
正如预期一样,6380 端口实例的从数据库变为了两个,6379 成功恢复服务。
# 哨兵的原理
一个哨兵进程启动时会读取配置文件的内容,通过如下的配置找出需要监控的主数据库:
sentinel monitor master-name ip redis-port quorum
其中:
- master-name 是一个由大小写字母、数字和“. - _”组成的主数据库的名字,因为考虑到故障恢复后当前监控的系统的主数据库的地址和端口会产生变化,所以哨兵提供了命令可以通过主数据库的名字获取当前系统的主数据库的地址和端口号。
- ip 表示当前系统中主数据库的地址,而 redis-port 则表示端口号。
- quorum 用来表示执行故障恢复操作前至少需要几个哨兵节点同意,一般是半数以上。
# 多个哨兵
哨兵以独立进程的方式对一个主从系统进行监控,监控的效果好坏与否取决于哨兵的视角是否有代表性。如果一个主从系统中配置的哨兵较少,哨兵对整个系统的判断的可靠性就会降低。
极端情况下,当只有一个哨兵时,哨兵本身就可能会发生单点故障。整体来讲,相对稳妥的哨兵部署方案是使得哨兵的视角尽可能地与每个节点的视角一致,即:
- 为每个节点(无论是主数据库还是从数据库)部署一个哨兵;
- 使每个哨兵与其对应的节点的网络环境相同或相近。
这样的部署方案可以保证哨兵的视角拥有较高的代表性和可靠性。举例一个例子:当网络分区后,如果哨兵认为某个分区是主要分区,即意味着从每个节点观察,该分区均为主分区。
同时设置 quorum 的值为 N/2 + 1(其中 N 为哨兵节点数量),这样使得只有当大部分哨兵节点同意后才会进行故障恢复。