前面章节介绍了 Redis 的主从复制,主从复制有一个致命的问题,即当 Master 服务器宕掉时,不会自动切换 Master,需要人为干预。鉴于这个问题,Redis 提供了哨兵功能。
哨兵是 Redis 集群架构中非常重要的一个组件,哨兵的出现主要是解决了主从复制出现故障时需要人为干预的问题,哨兵实现了自动化的故障恢复。如下图:
上图中,Sentinel(哨兵)分别监听了 Master、Slave 节点,当 Master 宕机后哨兵实现了自动化的故障恢复,即重新选择新的 Master。
注意:在配置哨兵模式之前,需要提前配置好 Master-Slave 主从复制模式,如不知道怎样配置,请参考“Redis 主从复制”。
哨兵模式是基于主从模式的,解决了主从模式中 Master 服务器故障不可以自动切换故障的问题。
(1)它是一种中心化的集群实现方案,始终只有一个 Redis 主机来接收和处理写请求,写操作受单机瓶颈影响。
(2)集群里所有节点保存的都是全量数据,浪费内存空间,没有真正实现分布式存储。数据量过大时,主从同步严重影响 Master 服务器的性能。
(3)Master 宕机后,有一段时间 Redis 是不可写的。因为投票选举结束之前,谁也不知道主机和从机是谁,并且 Redis 也会开启保护机制,禁止写操作,直到选举出了新的 Master。
(1)集群监控:负责监控 Redis Master 和 Slave 进程是否正常工作
(2)消息通知:如果某个 Redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员
(3)故障转移:如果 Master 服务器挂掉了,会自动转移到 Slave 服务器上
(4)配置中心:如果故障转移发生了,通知 Client 客户端新的 Master 地址
下面将介绍哨兵模式中哨兵是怎样监控各个节点的,具体流程如下:
(1)Master 节点的信息配置在哨兵(Sentinel)的配置文件中
(2)哨兵节点会和配置的 Master 节点建立起两条连接命令连接和订阅连接
(3)哨兵会通过命令连接,每 10s 发送一次 INFO 命令,通过 INFO 命令,主节点会返回自己的 run_id 和自己的从节点信息。
(4)哨兵会对这些 Slave 节点也建立两条连接命令连接和订阅连接。
(5)哨兵通过命令连接向 Slave 节点发送 INFO 命令,获取到他的一些信息,如 run_id(Redis 服务器 id)、role(职能)、从服务器的复制偏移量 offset以及其他信息
(6)通过命令连接向服务器的 sentinel:hello 频道发送一条消息,内容包括自己的 ip、端口、run_id、配置(后续投票的时候会用到)等。
(7)通过订阅连接对服务器的 sentinel:hello 频道做了监听,所以所有的向该频道发送的哨兵的消息都能被接受到。
(8)解析监听到的消息,进行分析提取,就可以知道还有那些别的哨兵服务节点也在监听这些主从节点了,更新结构体将这些哨兵节点记录下来。
(9)向观察到的其他的哨兵节点建立命令连接→没有订阅连接。
哨兵 (Sentinel) 节点会每秒一次的频率向建立了命令连接的实例发送 PING 命令,如果在 down-after--milliseconds 毫秒内没有做出有效响应包括 (PONG/ LOADINC/MASTERDOWN) 以外的响应,哨兵就会将该实例在本结构体中的状态标记为 SRI_S_DOWN 主观下线。
当一个哨兵节点发现主节点处于主观下线状态,会向其他的哨兵节点发出询问,该节点是不是已经主观下线了。如果超过配置参数 quorum 个节点认为是主观下线时,该哨兵节点就会将自己维护的结构体中该主节点标记为 SRIO DOWN 客观下线询问命令 SENTINEL is-master-down-by-addr。
在认为主节点客观下线的情况下,哨兵节点节点间会发起一 次选举,命令为:SENTINEL is-master-down-by-addr。
只是 runid 这次会将自己的 runid 带进去, 希望接受者将自己设置为主节点。如果超过半数以上的节点返回将该节点标记为 leacer 的情况下,会有该 leader 对故障进行迁移。
在从节点中挑选出新的主节点
(1)通讯正常
(2)优先级排序
(3)优先级相同时选择 offset 最大的
将该节点设置成新的主节点 SLAVEOFnoone,并确保在后续的 ING0 命令时该节点返回状态为 master,将其他的从节点设置成从新的主节点复制,SLAVE0F 命令将旧的主节点变成新的主节点的从节点。
该实例将在单台 Windows 环境服务器下演示 Redis 哨兵模式的配置,服务节点信息如下:
Master 127.0.0.1:6379 Slave1 127.0.0.1:6378 Slave2 127.0.0.1:6377
注意:
(1)搭建 Redis 哨兵模式时需先搭建 Redis 主从复制(这是为什么呢?因为哨兵是用来解决 Redis 主从复制中 Master 宕掉后,自动选择一个 Slave 作为新的 Master)。
(2)哨兵模式配置需在一个单独的 sentinel.conf 配置文件中进行配置。
(3)通常情况下,一个 Redis 服务(不管是 Master 还是 Slave)均启动一个哨兵,即多哨兵。
下面将通过配置一个哨兵来简单介绍怎样为 Redis 主从复制配置哨兵。
注意,你可以选择一个单独的 Redis 实例来运行哨兵服务,当然也可以使用 Master 或 Slave 实例来运行哨兵服务。
默认情况下 Redis 没有提供哨兵的配置文件 sentinel.conf,因此,需要我们自己在 Redis 主目录,即 redis.conf 配置文件所在的目录下面创建 sentinel.conf 配置文件,配置文件可以从 Redis 源码包的 src 目录中找到默认的 sentinel.conf 文件,修改的配置内容如下:
# 是否开启保护模式,这里选择不开启 protected-mode no # 设置哨兵的端口 port 26379 # 设置哨兵服务是否后台运行,这里选择不后台运行,便于我们观察启动日志 # 正式环境,建议设置为 yes,后台启动 daemonize no # Sentinel去监视一个名为 mymaster 的主 redis 实例 # 这个主实例的 IP 地址为 127.0.0.1,端口号为6379 # 而将这个主实例判断为失效至少需要 2 个 Sentinel 进程的同意 # 只要同意 Sentinel 的数量不达标,自动 failover 就不会执行 sentinel monitor mymaster 127.0.0.1 6379 1 # 指定了 Sentinel 认为 Redis 实例已经失效所需的毫秒数 # 当实例超过该时间没有返回 PING,或者直接返回错误 # 那么 Sentinel 将这个实例标记为主观下线。 # 只有一个 Sentinel 进程将实例标记为主观下线并不一定会引起实例的自动故障迁移 # 只有在足够数量的 Sentinel 都将一个实例标记为主观下线之后 # 实例才会被标记为客观下线,这时自动故障迁移才会执行 sentinel down-after-milliseconds mymaster 5000 # 设置连接 master 和 slave 时的密码,注意 sentinel 不能分别为 master # 和 slave 设置不同的密码,因此 master 和 slave 的密码应该设置相同 sentinel auth-pass mymaster aaaaaa # 指定了在执行故障转移时,最多可以有多少个从 Redis 实例在同步新的主实例 # 在 Redis 从(Slave)实例较多的情况下这个数字越小,同步的时间越长,完成故障转移所需的时间就越长 sentinel config-epoch mymaster 4
运行哨兵模式和运行 Redis 服务有点不一样,需要通过 --sentinel 选项来启动哨兵。命令如下:
redis-server.exe sentinel.conf --sentinel
执行上面命令将启动哨兵服务,日志如下:
[49660] 04 Apr 13:06:39.987 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo [49660] 04 Apr 13:06:39.988 # Redis version=5.0.14.1, bits=64, commit=ec77f72d, modified=0, pid=49660, just started [49660] 04 Apr 13:06:39.988 # Configuration loaded _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 5.0.14.1 (ec77f72d/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in sentinel mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 26379 | `-._ `._ / _.-' | PID: 49660 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' [49660] 04 Apr 13:06:39.992 # Sentinel ID is 19e18f6594d97e540e075ca27bd73708911ad102 [49660] 04 Apr 13:06:39.992 # +monitor master mymaster 127.0.0.1 6379 quorum 1
通过 redis-cli 命令连接到哨兵服务,运行 info sentinel 命令查看哨兵服务信息,命令如下:
C:\Users\Administrator>redis-cli -p 26379 127.0.0.1:26379> info sentinel # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=mymaster,status=sdown,address=127.0.0.1:6379,slaves=2,sentinels=1
验证详细步骤如下:
(1)先查看 Redis 主从复制的服务信息,如下:
C:\Users\Administrator>redis-cli 127.0.0.1:6379> info replication # Replication role:master connected_slaves:2 slave0:ip=127.0.0.1,port=6378,state=online,offset=54297,lag=1 slave1:ip=127.0.0.1,port=6377,state=online,offset=54297,lag=1 master_replid:71696462f65b3c97ab4f58dff865824841a0352f master_replid2:0000000000000000000000000000000000000000 master_repl_offset:54297 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:54297
(2)关闭 Master 服务
(3)观察哨兵服务的输出日志,哨兵服务多出如下日志:
[49660] 04 Apr 13:07:48.967 # +sdown master mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:48.967 # +odown master mymaster 127.0.0.1 6379 #quorum 1/1 [49660] 04 Apr 13:07:48.967 # +new-epoch 5 [49660] 04 Apr 13:07:48.967 # +try-failover master mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:48.969 # +vote-for-leader 19e18f6594d97e540e075ca27bd73708911ad102 5 [49660] 04 Apr 13:07:48.969 # +elected-leader master mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:48.969 # +failover-state-select-slave master mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:49.044 # +selected-slave slave 127.0.0.1:6377 127.0.0.1 6377 @ mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:49.044 * +failover-state-send-slaveof-noone slave 127.0.0.1:6377 127.0.0.1 6377 @ mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:49.107 * +failover-state-wait-promotion slave 127.0.0.1:6377 127.0.0.1 6377 @ mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:49.990 # +promoted-slave slave 127.0.0.1:6377 127.0.0.1 6377 @ mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:49.990 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:50.066 * +slave-reconf-sent slave 127.0.0.1:6378 127.0.0.1 6378 @ mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:51.045 * +slave-reconf-inprog slave 127.0.0.1:6378 127.0.0.1 6378 @ mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:51.045 * +slave-reconf-done slave 127.0.0.1:6378 127.0.0.1 6378 @ mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:51.108 # +failover-end master mymaster 127.0.0.1 6379 [49660] 04 Apr 13:07:51.108 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6377
通过上面日志信息可知,哨兵服务选择 6377(即Slave2)服务为新的 Master。
(4)再次连接 6377 服务,查看主从复制服务信息,如下:
C:\Users\Administrator>redis-cli -p 6377 127.0.0.1:6377> info replication # Replication role:master connected_slaves:1 slave0:ip=127.0.0.1,port=6378,state=online,offset=10253,lag=1 master_replid:1e7e3125a215749c8b26b3405a9f7de3cabfe270 master_replid2:ccb61d5c613f6abb655b38f0aa9d2684403a6c49 master_repl_offset:10253 second_repl_offset:5226 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:10253
上面日志表面,当前服务(6377)为 Master 角色,拥有一个 Slave 节点。