深刻剖析Redis系列(二) - Redis哨兵模式与高可用集群

前言

Redis主从复制 模式下,一旦 主节点 因为故障不能提供服务,须要手动将 从节点 晋升为 主节点,同时还要通知 客户端 更新 主节点地址,这种故障处理方式从必定程度上是没法接受的。Redis 2.8 之后提供了 Redis Sentinel 哨兵机制 来解决这个问题。正则表达式

其余文章

正文

1. Redis高可用概述

Web 服务器中,高可用 是指服务器能够 正常访问 的时间,衡量的标准是在 多长时间 内能够提供正常服务(99.9%99.99%99.999% 等等)。在 Redis 层面,高可用 的含义要宽泛一些,除了保证提供 正常服务(如 主从分离快速容灾技术 等),还须要考虑 数据容量扩展数据安全 等等。数据结构

Redis 中,实现 高可用 的技术主要包括 持久化复制哨兵集群,下面简单说明它们的做用,以及解决了什么样的问题:

  • 持久化:持久化是 最简单的 高可用方法。它的主要做用是 数据备份,即将数据存储在 硬盘,保证数据不会因进程退出而丢失。

  • 复制:复制是高可用 Redis 的基础,哨兵集群 都是在 复制基础 上实现高可用的。复制主要实现了数据的多机备份以及对于读操做的负载均衡和简单的故障恢复。缺陷是故障恢复没法自动化、写操做没法负载均衡、存储能力受到单机的限制。

  • 哨兵:在复制的基础上,哨兵实现了 自动化故障恢复。缺陷是 写操做 没法 负载均衡存储能力 受到 单机 的限制。

  • 集群:经过集群,Redis 解决了 写操做 没法 负载均衡 以及 存储能力 受到 单机限制 的问题,实现了较为 完善高可用方案

2. Redis Sentinel的基本概念

Redis SentinelRedis 高可用 的实现方案。Sentinel 是一个管理多个 Redis 实例的工具,它能够实现对 Redis监控通知自动故障转移。下面先对 Redis Sentinel基本概念 进行简单的介绍。

基本名词说明:

基本名词 逻辑结构 物理结构
Redis数据节点 主节点和从节点 主节点和从节点的进程
主节点(master) Redis主数据库 一个独立的Redis进程
从节点(slave) Redis从数据库 一个独立的Redis进程
Sentinel节点 监控Redis数据节点 一个独立的Sentinel进程
Sentinel节点集合 若干Sentinel节点的抽象组合 若干Sentinel节点进程
Redis Sentinel Redis高可用实现方案 Sentinel节点集合和Redis数据节点进程
应用客户端 泛指一个或多个客户端 一个或者多个客户端进程或者线程

如图所示,Redis主从复制模式Sentinel 高可用架构 的示意图:

3. Redis主从复制的问题

Redis 主从复制 可将 主节点 数据同步给 从节点,从节点此时有两个做用:

  1. 一旦 主节点宕机从节点 做为 主节点备份 能够随时顶上来。
  2. 扩展 主节点读能力,分担主节点读压力。

主从复制 同时存在如下几个问题:

  1. 一旦 主节点宕机从节点 晋升成 主节点,同时须要修改 应用方主节点地址,还须要命令全部 从节点复制 新的主节点,整个过程须要 人工干预

  2. 主节点写能力 受到 单机的限制

  3. 主节点存储能力 受到 单机的限制

  4. 原生复制 的弊端在早期的版本中也会比较突出,好比:Redis 复制中断 后,从节点 会发起 psync。此时若是 同步不成功,则会进行 全量同步主库 执行 全量备份 的同时,可能会形成毫秒或秒级的 卡顿

4. Redis Sentinel深刻探究

4.1. Redis Sentinel的架构

4.2. Redis Sentinel的主要功能

Sentinel 的主要功能包括 主节点存活检测主从运行状况检测自动故障转移failover)、主从切换RedisSentinel 最小配置是 一主一从

RedisSentinel 系统能够用来管理多个 Redis 服务器,该系统能够执行如下四个任务:

  • 监控

Sentinel 会不断的检查 主服务器从服务器 是否正常运行。

  • 通知

当被监控的某个 Redis 服务器出现问题,Sentinel 经过 API 脚本管理员 或者其余的 应用程序 发送通知。

  • 自动故障转移

主节点 不能正常工做时,Sentinel 会开始一次 自动的 故障转移操做,它会将与 失效主节点主从关系 的其中一个 从节点 升级为新的 主节点,而且将其余的 从节点 指向 新的主节点

  • 配置提供者

Redis Sentinel 模式下,客户端应用 在初始化时链接的是 Sentinel 节点集合,从中获取 主节点 的信息。

4.3. 主观下线和客观下线

默认状况下,每一个 Sentinel 节点会以 每秒一次 的频率对 Redis 节点和 其它Sentinel 节点发送 PING 命令,并经过节点的 回复 来判断节点是否在线。

  • 主观下线

主观下线 适用于全部 主节点从节点。若是在 down-after-milliseconds 毫秒内,Sentinel 没有收到 目标节点 的有效回复,则会断定 该节点主观下线

  • 客观下线

客观下线 只适用于 主节点。若是 主节点 出现故障,Sentinel 节点会经过 sentinel is-master-down-by-addr 命令,向其它 Sentinel 节点询问对该节点的 状态判断。若是超过 <quorum> 个数的节点断定 主节点 不可达,则该 Sentinel 节点会判断 主节点客观下线

4.4. Sentinel的通讯命令

Sentinel 节点链接一个 Redis 实例的时候,会建立 cmdpub/sub 两个 链接Sentinel 经过 cmd 链接给 Redis 发送命令,经过 pub/sub 链接到 Redis 实例上的其余 Sentinel 实例。

SentinelRedis 主节点从节点 交互的命令,主要包括:

命令 做 用
PING SentinelRedis 节点发送 PING 命令,检查节点的状态
INFO SentinelRedis 节点发送 INFO 命令,获取它的 从节点信息
PUBLISH Sentinel 向其监控的 Redis 节点 __sentinel__:hello 这个 channel 发布 本身的信息主节点 相关的配置
SUBSCRIBE Sentinel 经过订阅 Redis 主节点从节点__sentinel__:hello 这个 channnel,获取正在监控相同服务的其余 Sentinel 节点

SentinelSentinel 交互的命令,主要包括:

命令 做 用
PING Sentinel 向其余 Sentinel 节点发送 PING 命令,检查节点的状态
SENTINEL:is-master-down-by-addr 和其余 Sentinel 协商 主节点 的状态,若是 主节点 处于 SDOWN 状态,则投票自动选出新的 主节点

4.5. Redis Sentinel的工做原理

每一个 Sentinel 节点都须要 按期执行 如下任务:

  • 每一个 Sentinel每秒钟 一次的频率,向它所知的 主服务器从服务器 以及其余 Sentinel 实例 发送一个 PING 命令。

  1. 若是一个 实例instance)距离 最后一次 有效回复 PING 命令的时间超过 down-after-milliseconds 所指定的值,那么这个实例会被 Sentinel 标记为 主观下线

  1. 若是一个 主服务器 被标记为 主观下线,那么正在 监视 这个 主服务器 的全部 Sentinel 节点,要以 每秒一次 的频率确认 主服务器 的确进入了 主观下线 状态。

  1. 若是一个 主服务器 被标记为 主观下线,而且有 足够数量Sentinel(至少要达到 配置文件 指定的数量)在指定的 时间范围 内赞成这一判断,那么这个 主服务器 被标记为 客观下线

  1. 在通常状况下, 每一个 Sentinel 会以每 10 秒一次的频率,向它已知的全部 主服务器从服务器 发送 INFO 命令。当一个 主服务器Sentinel 标记为 客观下线 时,Sentinel下线主服务器 的全部 从服务器 发送 INFO 命令的频率,会从 10 秒一次改成 每秒一次

  1. Sentinel 和其余 Sentinel 协商 主节点 的状态,若是 主节点 处于 SDOWN 状态,则投票自动选出新的 主节点。将剩余的 从节点 指向 新的主节点 进行 数据复制

  1. 当没有足够数量的 Sentinel 赞成 主服务器 下线时, 主服务器客观下线状态 就会被移除。当 主服务器 从新向 SentinelPING 命令返回 有效回复 时,主服务器主观下线状态 就会被移除。

注意:一个有效的 PING 回复能够是:+PONG-LOADING 或者 -MASTERDOWN。若是 服务器 返回除以上三种回复以外的其余回复,又或者在 指定时间 内没有回复 PING 命令, 那么 Sentinel 认为服务器返回的回复 无效non-valid)。

5. Redis Sentinel搭建

5.1. Redis Sentinel的部署须知

  1. 一个稳健的 Redis Sentinel 集群,应该使用至少 三个 Sentinel 实例,而且保证讲这些实例放到 不一样的机器 上,甚至不一样的 物理区域

  2. Sentinel 没法保证 强一致性

  3. 常见的 客户端应用库 都支持 Sentinel

  4. Sentinel 须要经过不断的 测试观察,才能保证高可用。

5.2. Redis Sentinel的配置文件

# 哨兵sentinel实例运行的端口,默认26379 
port 26379
# 哨兵sentinel的工做目录
dir ./

# 哨兵sentinel监控的redis主节点的 
## ip:主机ip地址
## port:哨兵端口号
## master-name:能够本身命名的主节点名字(只能由字母A-z、数字0-9 、这三个字符".-_"组成。)
## quorum:当这些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 auth-pass <master-name> <password> 
sentinel auth-pass mymaster 123456  

# 指定主节点应答哨兵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

# 当sentinel有任何警告级别的事件发生时(好比说redis实例的主观失效和客观失效等等),将会去调用这个脚本。一个脚本的最大执行时间为60s,若是超过这个时间,脚本将会被一个SIGKILL信号终止,以后从新执行。
# 对于脚本的运行结果有如下规则: 
## 1. 若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10。
## 2. 若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。 
## 3. 若是脚本在执行过程当中因为收到系统中断信号被终止了,则同返回值为1时的行为相同。
# sentinel notification-script <master-name> <script-path> 
sentinel notification-script mymaster /var/redis/notify.sh

# 这个脚本应该是通用的,能被屡次调用,不是针对性的。
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
复制代码

5.3. Redis Sentinel的节点规划

角色 IP地址 端口号
Redis Master 10.206.20.231 16379
Redis Slave1 10.206.20.231 26379
Redis Slave2 10.206.20.231 36379
Redis Sentinel1 10.206.20.231 16380
Redis Sentinel2 10.206.20.231 26380
Redis Sentinel3 10.206.20.231 36380

5.4. Redis Sentinel的配置搭建

5.4.1. Redis-Server的配置管理

分别拷贝三份 redis.conf 文件到 /usr/local/redis-sentinel 目录下面。三个配置文件分别对应 masterslave1slave2 三个 Redis 节点的 启动配置

$ sudo cp /usr/local/redis-4.0.11/redis.conf /usr/local/redis-sentinel/redis-16379.conf
$ sudo cp /usr/local/redis-4.0.11/redis.conf /usr/local/redis-sentinel/redis-26379.conf
$ sudo cp /usr/local/redis-4.0.11/redis.conf /usr/local/redis-sentinel/redis-36379.conf
复制代码

分别修改三份配置文件以下:

  • 主节点:redis-16379.conf
daemonize yes
pidfile /var/run/redis-16379.pid
logfile /var/log/redis/redis-16379.log
port 16379
bind 0.0.0.0
timeout 300
databases 16
dbfilename dump-16379.db
dir ./redis-workdir
masterauth 123456
requirepass 123456
复制代码
  • 从节点1:redis-26379.conf
daemonize yes
pidfile /var/run/redis-26379.pid
logfile /var/log/redis/redis-26379.log
port 26379
bind 0.0.0.0
timeout 300
databases 16
dbfilename dump-26379.db
dir ./redis-workdir
masterauth 123456
requirepass 123456
slaveof 127.0.0.1 16379
复制代码
  • 从节点2:redis-36379.conf
daemonize yes
pidfile /var/run/redis-36379.pid
logfile /var/log/redis/redis-36379.log
port 36379
bind 0.0.0.0
timeout 300
databases 16
dbfilename dump-36379.db
dir ./redis-workdir
masterauth 123456
requirepass 123456
slaveof 127.0.0.1 16379
复制代码

若是要作 自动故障转移,建议全部的 redis.conf 都设置 masterauth。由于 自动故障 只会重写 主从关系,即 slaveof,不会自动写入 masterauth。若是 Redis 本来没有设置密码,则能够忽略。

5.4.2. Redis-Server启动验证

按顺序分别启动 163792637936379 三个 Redis 节点,启动命令和启动日志以下:

Redis 的启动命令:

$ sudo redis-server /usr/local/redis-sentinel/redis-16379.conf
$ sudo redis-server /usr/local/redis-sentinel/redis-26379.conf
$ sudo redis-server /usr/local/redis-sentinel/redis-36379.conf
复制代码

查看 Redis 的启动进程:

$ ps -ef | grep redis-server
    0  7127     1   0  2:16下午 ??         0:01.84 redis-server 0.0.0.0:16379 
    0  7133     1   0  2:16下午 ??         0:01.73 redis-server 0.0.0.0:26379 
    0  7137     1   0  2:16下午 ??         0:01.70 redis-server 0.0.0.0:36379 
复制代码

查看 Redis 的启动日志:

  • 节点 redis-16379
$ cat /var/log/redis/redis-16379.log 
7126:C 22 Aug 14:16:38.907 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7126:C 22 Aug 14:16:38.908 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7126, just started
7126:C 22 Aug 14:16:38.908 # Configuration loaded
7127:M 22 Aug 14:16:38.910 * Increased maximum number of open files to 10032 (it was originally set to 256).
7127:M 22 Aug 14:16:38.912 * Running mode=standalone, port=16379.
7127:M 22 Aug 14:16:38.913 # Server initialized
7127:M 22 Aug 14:16:38.913 * Ready to accept connections
7127:M 22 Aug 14:16:48.416 * Slave 127.0.0.1:26379 asks for synchronization
7127:M 22 Aug 14:16:48.416 * Full resync requested by slave 127.0.0.1:26379
7127:M 22 Aug 14:16:48.416 * Starting BGSAVE for SYNC with target: disk
7127:M 22 Aug 14:16:48.416 * Background saving started by pid 7134
7134:C 22 Aug 14:16:48.433 * DB saved on disk
7127:M 22 Aug 14:16:48.487 * Background saving terminated with success
7127:M 22 Aug 14:16:48.494 * Synchronization with slave 127.0.0.1:26379 succeeded
7127:M 22 Aug 14:16:51.848 * Slave 127.0.0.1:36379 asks for synchronization
7127:M 22 Aug 14:16:51.849 * Full resync requested by slave 127.0.0.1:36379
7127:M 22 Aug 14:16:51.849 * Starting BGSAVE for SYNC with target: disk
7127:M 22 Aug 14:16:51.850 * Background saving started by pid 7138
7138:C 22 Aug 14:16:51.862 * DB saved on disk
7127:M 22 Aug 14:16:51.919 * Background saving terminated with success
7127:M 22 Aug 14:16:51.923 * Synchronization with slave 127.0.0.1:36379 succeeded
复制代码

如下两行日志日志代表,redis-16379 做为 Redis主节点redis-26379redis-36379 做为 从节点,从 主节点 同步数据。

7127:M 22 Aug 14:16:48.416 * Slave 127.0.0.1:26379 asks for synchronization
7127:M 22 Aug 14:16:51.848 * Slave 127.0.0.1:36379 asks for synchronization
复制代码
  • 节点 redis-26379
$ cat /var/log/redis/redis-26379.log 
7132:C 22 Aug 14:16:48.407 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7132:C 22 Aug 14:16:48.408 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7132, just started
7132:C 22 Aug 14:16:48.408 # Configuration loaded
7133:S 22 Aug 14:16:48.410 * Increased maximum number of open files to 10032 (it was originally set to 256).
7133:S 22 Aug 14:16:48.412 * Running mode=standalone, port=26379.
7133:S 22 Aug 14:16:48.413 # Server initialized
7133:S 22 Aug 14:16:48.413 * Ready to accept connections
7133:S 22 Aug 14:16:48.413 * Connecting to MASTER 127.0.0.1:16379
7133:S 22 Aug 14:16:48.413 * MASTER <-> SLAVE sync started
7133:S 22 Aug 14:16:48.414 * Non blocking connect for SYNC fired the event.
7133:S 22 Aug 14:16:48.414 * Master replied to PING, replication can continue...
7133:S 22 Aug 14:16:48.415 * Partial resynchronization not possible (no cached master)
7133:S 22 Aug 14:16:48.417 * Full resync from master: 211d3b4eceaa3af4fe5c77d22adf06e1218e0e7b:0
7133:S 22 Aug 14:16:48.494 * MASTER <-> SLAVE sync: receiving 176 bytes from master
7133:S 22 Aug 14:16:48.495 * MASTER <-> SLAVE sync: Flushing old data
7133:S 22 Aug 14:16:48.496 * MASTER <-> SLAVE sync: Loading DB in memory
7133:S 22 Aug 14:16:48.498 * MASTER <-> SLAVE sync: Finished with success
复制代码
  • 节点 redis-36379
$ cat /var/log/redis/redis-36379.log 
7136:C 22 Aug 14:16:51.839 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7136:C 22 Aug 14:16:51.840 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7136, just started
7136:C 22 Aug 14:16:51.841 # Configuration loaded
7137:S 22 Aug 14:16:51.843 * Increased maximum number of open files to 10032 (it was originally set to 256).
7137:S 22 Aug 14:16:51.845 * Running mode=standalone, port=36379.
7137:S 22 Aug 14:16:51.845 # Server initialized
7137:S 22 Aug 14:16:51.846 * Ready to accept connections
7137:S 22 Aug 14:16:51.846 * Connecting to MASTER 127.0.0.1:16379
7137:S 22 Aug 14:16:51.847 * MASTER <-> SLAVE sync started
7137:S 22 Aug 14:16:51.847 * Non blocking connect for SYNC fired the event.
7137:S 22 Aug 14:16:51.847 * Master replied to PING, replication can continue...
7137:S 22 Aug 14:16:51.848 * Partial resynchronization not possible (no cached master)
7137:S 22 Aug 14:16:51.850 * Full resync from master: 211d3b4eceaa3af4fe5c77d22adf06e1218e0e7b:14
7137:S 22 Aug 14:16:51.923 * MASTER <-> SLAVE sync: receiving 176 bytes from master
7137:S 22 Aug 14:16:51.923 * MASTER <-> SLAVE sync: Flushing old data
7137:S 22 Aug 14:16:51.924 * MASTER <-> SLAVE sync: Loading DB in memory
7137:S 22 Aug 14:16:51.927 * MASTER <-> SLAVE sync: Finished with success
复制代码

5.4.3. Sentinel的配置管理

分别拷贝三份 redis-sentinel.conf 文件到 /usr/local/redis-sentinel 目录下面。三个配置文件分别对应 masterslave1slave2 三个 Redis 节点的 哨兵配置

$ sudo cp /usr/local/redis-4.0.11/sentinel.conf /usr/local/redis-sentinel/sentinel-16380.conf
$ sudo cp /usr/local/redis-4.0.11/sentinel.conf /usr/local/redis-sentinel/sentinel-26380.conf
$ sudo cp /usr/local/redis-4.0.11/sentinel.conf /usr/local/redis-sentinel/sentinel-36380.conf
复制代码
  • 节点1:sentinel-16380.conf
protected-mode no
bind 0.0.0.0
port 16380
daemonize yes
sentinel monitor master 127.0.0.1 16379 2
sentinel down-after-milliseconds master 5000
sentinel failover-timeout master 180000
sentinel parallel-syncs master 1
sentinel auth-pass master 123456
logfile /var/log/redis/sentinel-16380.log
复制代码
  • 节点2:sentinel-26380.conf
protected-mode no
bind 0.0.0.0
port 26380
daemonize yes
sentinel monitor master 127.0.0.1 16379 2
sentinel down-after-milliseconds master 5000
sentinel failover-timeout master 180000
sentinel parallel-syncs master 1
sentinel auth-pass master 123456
logfile /var/log/redis/sentinel-26380.log
复制代码
  • 节点3:sentinel-36380.conf
protected-mode no
bind 0.0.0.0
port 36380
daemonize yes
sentinel monitor master 127.0.0.1 16379 2
sentinel down-after-milliseconds master 5000
sentinel failover-timeout master 180000
sentinel parallel-syncs master 1
sentinel auth-pass master 123456
logfile /var/log/redis/sentinel-36380.log
复制代码

5.4.4. Sentinel启动验证

按顺序分别启动 163802638036380 三个 Sentinel 节点,启动命令和启动日志以下:

$ sudo redis-sentinel /usr/local/redis-sentinel/sentinel-16380.conf
$ sudo redis-sentinel /usr/local/redis-sentinel/sentinel-26380.conf
$ sudo redis-sentinel /usr/local/redis-sentinel/sentinel-36380.conf
复制代码

查看 Sentinel 的启动进程:

$ ps -ef | grep redis-sentinel
    0  7954     1   0  3:30下午 ??         0:00.05 redis-sentinel 0.0.0.0:16380 [sentinel] 
    0  7957     1   0  3:30下午 ??         0:00.05 redis-sentinel 0.0.0.0:26380 [sentinel] 
    0  7960     1   0  3:30下午 ??         0:00.04 redis-sentinel 0.0.0.0:36380 [sentinel] 
复制代码

查看 Sentinel 的启动日志:

  • 节点 sentinel-16380
$ cat /var/log/redis/sentinel-16380.log 
7953:X 22 Aug 15:30:27.245 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7953:X 22 Aug 15:30:27.245 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7953, just started
7953:X 22 Aug 15:30:27.245 # Configuration loaded
7954:X 22 Aug 15:30:27.247 * Increased maximum number of open files to 10032 (it was originally set to 256).
7954:X 22 Aug 15:30:27.249 * Running mode=sentinel, port=16380.
7954:X 22 Aug 15:30:27.250 # Sentinel ID is 69d05b86a82102a8919231fd3c2d1f21ce86e000
7954:X 22 Aug 15:30:27.250 # +monitor master master 127.0.0.1 16379 quorum 2
7954:X 22 Aug 15:30:32.286 # +sdown sentinel fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 127.0.0.1 36380 @ master 127.0.0.1 16379
7954:X 22 Aug 15:30:34.588 # -sdown sentinel fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 127.0.0.1 36380 @ master 127.0.0.1 16379
复制代码

sentinel-16380 节点的 Sentinel ID69d05b86a82102a8919231fd3c2d1f21ce86e000,并经过 Sentinel ID 把自身加入 sentinel 集群中。

  • 节点 sentinel-26380
$ cat /var/log/redis/sentinel-26380.log 
7956:X 22 Aug 15:30:30.900 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7956:X 22 Aug 15:30:30.901 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7956, just started
7956:X 22 Aug 15:30:30.901 # Configuration loaded
7957:X 22 Aug 15:30:30.904 * Increased maximum number of open files to 10032 (it was originally set to 256).
7957:X 22 Aug 15:30:30.905 * Running mode=sentinel, port=26380.
7957:X 22 Aug 15:30:30.906 # Sentinel ID is 21e30244cda6a3d3f55200bcd904d0877574e506
7957:X 22 Aug 15:30:30.906 # +monitor master master 127.0.0.1 16379 quorum 2
7957:X 22 Aug 15:30:30.907 * +slave slave 127.0.0.1:26379 127.0.0.1 26379 @ master 127.0.0.1 16379
7957:X 22 Aug 15:30:30.911 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 16379
7957:X 22 Aug 15:30:36.311 * +sentinel sentinel fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 127.0.0.1 36380 @ master 127.0.0.1 16379
复制代码

sentinel-26380 节点的 Sentinel ID21e30244cda6a3d3f55200bcd904d0877574e506,并经过 Sentinel ID 把自身加入 sentinel 集群中。此时 sentinel 集群中已有 sentinel-16380sentinel-26380 两个节点。

  • 节点 sentinel-36380
$ cat /var/log/redis/sentinel-36380.log 
7959:X 22 Aug 15:30:34.273 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7959:X 22 Aug 15:30:34.274 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7959, just started
7959:X 22 Aug 15:30:34.274 # Configuration loaded
7960:X 22 Aug 15:30:34.276 * Increased maximum number of open files to 10032 (it was originally set to 256).
7960:X 22 Aug 15:30:34.277 * Running mode=sentinel, port=36380.
7960:X 22 Aug 15:30:34.278 # Sentinel ID is fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7
7960:X 22 Aug 15:30:34.278 # +monitor master master 127.0.0.1 16379 quorum 2
7960:X 22 Aug 15:30:34.279 * +slave slave 127.0.0.1:26379 127.0.0.1 26379 @ master 127.0.0.1 16379
7960:X 22 Aug 15:30:34.283 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 16379
7960:X 22 Aug 15:30:34.993 * +sentinel sentinel 21e30244cda6a3d3f55200bcd904d0877574e506 127.0.0.1 26380 @ master 127.0.0.1 16379
复制代码

sentinel-36380 节点的 Sentinel IDfd166dc66425dc1d9e2670e1f17cb94fe05f5fc7,并经过 Sentinel ID 把自身加入 sentinel 集群中。此时 sentinel 集群中已有 sentinel-16380sentinel-26380sentinel-36380 三个节点。

5.4.5. Sentinel配置刷新

  • 节点1:sentinel-16380.conf

sentinel-16380.conf 文件新生成以下的配置项:

# Generated by CONFIG REWRITE
dir "/usr/local/redis-sentinel"
sentinel config-epoch master 0
sentinel leader-epoch master 0
sentinel known-slave master 127.0.0.1 36379
sentinel known-slave master 127.0.0.1 26379
sentinel known-sentinel master 127.0.0.1 26380 21e30244cda6a3d3f55200bcd904d0877574e506
sentinel known-sentinel master 127.0.0.1 36380 fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7
sentinel current-epoch 0
复制代码

能够注意到,sentinel-16380.conf 刷新写入了 Redis 主节点关联的全部 从节点 redis-26379redis-36379,同时写入了其他两个 Sentinel 节点 sentinel-26380sentinel-36380IP 地址,端口号Sentinel ID

# Generated by CONFIG REWRITE
dir "/usr/local/redis-sentinel"
sentinel config-epoch master 0
sentinel leader-epoch master 0
sentinel known-slave master 127.0.0.1 26379
sentinel known-slave master 127.0.0.1 36379
sentinel known-sentinel master 127.0.0.1 36380 fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7
sentinel known-sentinel master 127.0.0.1 16380 69d05b86a82102a8919231fd3c2d1f21ce86e000
sentinel current-epoch 0
复制代码

能够注意到,sentinel-26380.conf 刷新写入了 Redis 主节点关联的全部 从节点 redis-26379redis-36379,同时写入了其他两个 Sentinel 节点 sentinel-36380sentinel-16380IP 地址,端口号Sentinel ID

# Generated by CONFIG REWRITE
dir "/usr/local/redis-sentinel"
sentinel config-epoch master 0
sentinel leader-epoch master 0
sentinel known-slave master 127.0.0.1 36379
sentinel known-slave master 127.0.0.1 26379
sentinel known-sentinel master 127.0.0.1 16380 69d05b86a82102a8919231fd3c2d1f21ce86e000
sentinel known-sentinel master 127.0.0.1 26380 21e30244cda6a3d3f55200bcd904d0877574e506
sentinel current-epoch 0
复制代码

能够注意到,sentinel-36380.conf 刷新写入了 Redis 主节点关联的全部 从节点 redis-26379redis-36379,同时写入了其他两个 Sentinel 节点 sentinel-16380sentinel-26380IP 地址,端口号Sentinel ID

5.5. Sentinel时客户端命令

  • 检查其余 Sentinel 节点的状态,返回 PONG 为正常。
> PING sentinel
复制代码
  • 显示被监控的全部 主节点 以及它们的状态。
> SENTINEL masters
复制代码
  • 显示指定 主节点 的信息和状态。
> SENTINEL master <master_name>
复制代码
  • 显示指定 主节点 的全部 从节点 以及它们的状态。
> SENTINEL slaves <master_name>
复制代码

返回指定 主节点IP 地址和 端口。若是正在进行 failover 或者 failover 已经完成,将会显示被提高为 主节点从节点IP 地址和 端口

> SENTINEL get-master-addr-by-name <master_name>
复制代码
  • 重置名字匹配该 正则表达式 的全部的 主节点 的状态信息,清除它以前的 状态信息,以及 从节点 的信息。
> SENTINEL reset <pattern>
复制代码
  • 强制当前 Sentinel 节点执行 failover,而且不须要获得其余 Sentinel 节点的赞成。可是 failover 后会将 最新的配置 发送给其余 Sentinel 节点。
SENTINEL failover <master_name>
复制代码

6. Redis Sentinel故障切换与恢复

6.1. Redis CLI客户端跟踪

上面的日志显示,redis-16379 节点为 主节点,它的进程 ID7127。为了模拟 Redis 主节点故障,强制杀掉这个进程。

$ kill -9 7127
复制代码

使用 redis-cli 客户端命令进入 sentinel-16380 节点,查看 Redis 节点 的状态信息。

$ redis-cli -p 16380
复制代码
  • 查看 Redis 主从集群的 主节点 信息。能够发现 redis-26379 晋升为 新的主节点
127.0.0.1:16380> SENTINEL master master
 1) "name"
 2) "master"
 3) "ip"
 4) "127.0.0.1"
 5) "port"
 6) "26379"
 7) "runid"
 8) "b8ca3b468a95d1be5efe1f50c50636cafe48c59f"
 9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "588"
19) "last-ping-reply"
20) "588"
21) "down-after-milliseconds"
22) "5000"
23) "info-refresh"
24) "9913"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "663171"
29) "config-epoch"
30) "1"
31) "num-slaves"
32) "2"
33) "num-other-sentinels"
34) "2"
35) "quorum"
36) "2"
37) "failover-timeout"
38) "180000"
39) "parallel-syncs"
40) "1"
复制代码

6.2. Redis Sentinel日志跟踪

查看任意 Sentinel 节点的日志以下:

7954:X 22 Aug 18:40:22.504 # +tilt #tilt mode entered
7954:X 22 Aug 18:40:32.197 # +tilt #tilt mode entered
7954:X 22 Aug 18:41:02.241 # -tilt #tilt mode exited
7954:X 22 Aug 18:48:24.550 # +sdown master master 127.0.0.1 16379
7954:X 22 Aug 18:48:24.647 # +new-epoch 1
7954:X 22 Aug 18:48:24.651 # +vote-for-leader fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 1
7954:X 22 Aug 18:48:25.678 # +odown master master 127.0.0.1 16379 #quorum 3/2
7954:X 22 Aug 18:48:25.678 # Next failover delay: I will not start a failover before Wed Aug 22 18:54:24 2018
7954:X 22 Aug 18:48:25.709 # +config-update-from sentinel fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 127.0.0.1 36380 @ master 127.0.0.1 16379
7954:X 22 Aug 18:48:25.710 # +switch-master master 127.0.0.1 16379 127.0.0.1 26379
7954:X 22 Aug 18:48:25.710 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 26379
7954:X 22 Aug 18:48:25.711 * +slave slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 26379
7954:X 22 Aug 18:48:30.738 # +sdown slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 26379
7954:X 22 Aug 19:38:23.479 # -sdown slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 26379
复制代码
  • 分析日志,能够发现 redis-16329 节点先进入 sdown 主观下线 状态。
+sdown master master 127.0.0.1 16379
复制代码
  • 哨兵检测到 redis-16329 出现故障,Sentinel 进入一个 新纪元,从 0 变为 1
+new-epoch 1
复制代码
  • 三个 Sentinel 节点开始协商 主节点 的状态,判断其是否须要 客观下线
+vote-for-leader fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 1
复制代码
  • 超过 quorum 个数的 Sentinel 节点认为 主节点 出现故障,redis-16329 节点进入 客观下线 状态。
+odown master master 127.0.0.1 16379 #quorum 3/2
复制代码
  • Sentinal 进行 自动故障切换,协商选定 redis-26329 节点做为新的 主节点
+switch-master master 127.0.0.1 16379 127.0.0.1 26379
复制代码
  • redis-36329 节点和已经 客观下线redis-16329 节点成为 redis-26479从节点
7954:X 22 Aug 18:48:25.710 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 26379
7954:X 22 Aug 18:48:25.711 * +slave slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 26379
复制代码

6.3. Redis的配置文件

分别查看三个 redis 节点的配置文件,发生 主从切换redis.conf 的配置会自动发生刷新。

  • 节点 redis-16379
daemonize yes
pidfile "/var/run/redis-16379.pid"
logfile "/var/log/redis/redis-16379.log"
port 16379
bind 0.0.0.0
timeout 300
databases 16
dbfilename "dump-16379.db"
dir "/usr/local/redis-sentinel/redis-workdir"
masterauth "123456"
requirepass "123456"
复制代码
  • 节点 redis-26379
daemonize yes
pidfile "/var/run/redis-26379.pid"
logfile "/var/log/redis/redis-26379.log"
port 26379
bind 0.0.0.0
timeout 300
databases 16
dbfilename "dump-26379.db"
dir "/usr/local/redis-sentinel/redis-workdir"
masterauth "123456"
requirepass "123456"
复制代码
  • 节点 redis-36379
daemonize yes
pidfile "/var/run/redis-36379.pid"
logfile "/var/log/redis/redis-36379.log"
port 36379
bind 0.0.0.0
timeout 300
databases 16
dbfilename "dump-36379.db"
dir "/usr/local/redis-sentinel/redis-workdir"
masterauth "123456"
requirepass "123456"
slaveof 127.0.0.1 26379
复制代码

分析redis-26379 节点 slaveof 配置被移除,晋升为 主节点redis-16379 节点处于 宕机状态redis-36379slaveof 配置更新为 127.0.0.1 redis-26379,成为 redis-26379从节点

重启节点 redis-16379。待正常启动后,再次查看它的 redis.conf 文件,配置以下:

daemonize yes
pidfile "/var/run/redis-16379.pid"
logfile "/var/log/redis/redis-16379.log"
port 16379
bind 0.0.0.0
timeout 300
databases 16
dbfilename "dump-16379.db"
dir "/usr/local/redis-sentinel/redis-workdir"
masterauth "123456"
requirepass "123456"
# Generated by CONFIG REWRITE
slaveof 127.0.0.1 26379
复制代码

节点 redis-16379 的配置文件新增一行 slaveof 配置属性,指向 redis-26379,即成为 新的主节点从节点

小结

本文首先对 Redis 实现高可用的几种模式作出了阐述,指出了 Redis 主从复制 的不足之处,进一步引入了 Redis Sentinel 哨兵模式 的相关概念,深刻说明了 Redis Sentinel具体功能基本原理高可用搭建自动故障切换 验证等。

固然,Redis Sentinel 仅仅解决了 高可用 的问题,对于 主节点 单点写入和单节点没法扩容等问题,还须要引入 Redis Cluster 集群模式 予以解决。

参考

《Redis 开发与运维》


欢迎关注技术公众号: 零壹技术栈

零壹技术栈

本账号将持续分享后端技术干货,包括虚拟机基础,多线程编程,高性能框架,异步、缓存和消息中间件,分布式和微服务,架构学习和进阶等学习资料和文章。

相关文章
相关标签/搜索