运维之道 | Redis 哨兵(Sentinel)深入剖析 及 Sentinel 搭建部署(高可用)

运维之道 | Redis 哨兵(Sentinel)深入剖析 及 Sentinel 搭建部署(高可用)

前言

Redis高可用概述

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

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

  • 持久化:持久化是最简单的高可用方法。它的主要作用是 数据备份,即将数据存储在 硬盘,保证数据不会因进程退出而丢失。
  • 主从复制:复制是高可用 Redis 的基础,哨兵和集群都是在复制基础上实现高可用的。复制主要实现了数据的多机备份以及对于读操作的负载均衡和简单的故障恢复。缺陷是故障恢复无法自动化、写操作无法负载均衡、存储能力受到单机的限制。
  • 哨兵:在复制的基础上,哨兵实现了自动化的故障恢复。缺陷是写操作无法负载均衡,存储能力受到单机的限制。
  • 集群:通过集群,Redis 解决了写操作无法负载均衡以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。

主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主从服务器,这就需要人工干预,既费时费力,还会造成一段时间内服务不可用,这不是一种推荐的方式,更多的时候,我们优先考虑哨兵模式,它是当前企业应用的主流方式。

Redis Sentinel 是 Redis 高可用 的实现方案。Sentinel 是一个管理多个 Redis 实例的工具,它可以实现对 Redis 的 监控、通知、自动故障转移

一、Redis Sentinel 的基本概念

1、Redis 的 主从复制模式Sentinel 高可用架构 的示意图

运维之道 | Redis 哨兵(Sentinel)深入剖析 及 Sentinel 搭建部署(高可用)_第1张图片

2、Redis Sentinel 的架构图

运维之道 | Redis 哨兵(Sentinel)深入剖析 及 Sentinel 搭建部署(高可用)_第2张图片

3、Redis Sentinel的主要功能

Sentinel 的主要功能包括:主节点存活检测主从运行情况检测自动故障转移 (failover)主从切换。Redis 的 Sentinel 最小配置是一主一从;

Redis 的 Sentinel 系统可以用来管理多个 Redis 服务器,该系统可以执行以下四个任务:

  • 监控: Sentinel 会不断的检查 主服务器从服务器 是否正常运行;
  • 通知: 当被监控的某个 Redis 服务器出现问题,Sentinel 通过 API 脚本 向 管理员 或者其他的 应用程序 发送通知;
  • 自动故障转移: 主节点 不能正常工作时,Sentinel 会开始一次 自动的故障转移操作,它会将与失效主节点是主从关系的其中一个从节点升级为新的 主节点,并且将其他的从节点指向新的主节点;
  • 配置提供者: 在 Redis Sentinel 模式下,客户端应用在初始化时连接的是 Sentinel 节点集合,从中获取 主节点 的信息;

4、主观下线和客观下线

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

  • 主观下线: 主观下线 适用于所有 主节点从节点。如果在 down-after-milliseconds毫秒内,Sentinel 没有收到 目标节点 的有效回复,则会判定 该节点 为 主观下线;
  • 客观下线: 客观下线 只适用于 主节点。如果 主节点 出现故障,Sentinel 节点会通过 sentinel is-master-down-by-addr 命令,向其它 Sentinel 节点询问对该节点的 状态判断。如果超过 个数的节点判定 主节点 不可达,则该 Sentinel 节点会判断 主节点 为 客观下线

5、Sentinel的通信命令

Sentinel 节点连接一个 Redis 实例的时候,会创建 cmdpub/sub两个 连接。Sentinel 通过 cmd 连接给 Redis 发送命令通过 pub/sub 连接到 Redis 实例上的其他 Sentinel 实例

Sentinel与Redis主节点和从节点交互的命令

命令 作 用
PING Sentinel 向 Redis 节点发送 PING 命令,检查节点的状态
INFO Sentinel 向 Redis 节点发送 INFO 命令,获取它的 从节点信息
PUBLISH Sentinel 向其监控的 Redis 节点 sentinel:hello 这个 channel 发布 自己的信息 及 主节点 相关的配置
SUBSCRIBE Sentinel 通过订阅 Redis 主节点 和 从节点 的 sentinel:hello 这个 channnel,获取正在监控相同服务的其他 Sentinel 节点

Sentinel 与 Sentinel 交互的命令

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

6、Redis Sentinel的工作原理

每个 Sentinel 节点都需要 定期执行 以下任务
每个 Sentinel 以 每秒钟 一次的频率,向它所知的 主服务器从服务器 以及其他 Sentinel 实例 发送一个 PING 命令
运维之道 | Redis 哨兵(Sentinel)深入剖析 及 Sentinel 搭建部署(高可用)_第3张图片
如果一个 实例(instance)距离 最后一次 有效回复 PING 命令的时间超过 down-after-milliseconds 所指定的值,那么这个实例会被 Sentinel 标记为 主观下线
运维之道 | Redis 哨兵(Sentinel)深入剖析 及 Sentinel 搭建部署(高可用)_第4张图片
如果一个 主服务器 被标记为 主观下线,那么正在监视这个主服务器的所有 Sentinel 节点要以每秒一次的频率确认主服务器的确进入了主观下线状态
运维之道 | Redis 哨兵(Sentinel)深入剖析 及 Sentinel 搭建部署(高可用)_第5张图片
如果一个 主服务器 被标记为 主观下线,并且有足够数量的 Sentinel(至少要达到 配置文件 指定的数量)在指定的 时间范围内同意这一判断,那么这个 主服务器 被标记为 客观下线。
运维之道 | Redis 哨兵(Sentinel)深入剖析 及 Sentinel 搭建部署(高可用)_第6张图片
在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率,向它已知的所有 主服务器从服务器发送INFO 命令。当一个 主服务器 被 Sentinel 标记为 客观下线 时,Sentinel 向下线主服务器 的所有从服务器 发送 INFO 命令的频率,会从 10 秒一次改为 每秒一次。
运维之道 | Redis 哨兵(Sentinel)深入剖析 及 Sentinel 搭建部署(高可用)_第7张图片
Sentinel 和其他 Sentinel 协商 主节点 的状态,如果 主节点 处于 SDOWN 状态,则投票自动选出新的 主节点。将剩余的从节点指向新的主节点进行数据复制
运维之道 | Redis 哨兵(Sentinel)深入剖析 及 Sentinel 搭建部署(高可用)_第8张图片
当没有足够数量的 Sentinel 同意主服务器下线时,主服务器的客观下线状态就会被移除。当主服务器重新向Sentinel 的PING命令返回有效回复时主服务器的主观下线状态就会被移除
运维之道 | Redis 哨兵(Sentinel)深入剖析 及 Sentinel 搭建部署(高可用)_第9张图片

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


二、Redis Sentinel搭建

1、Redis Sentinel 部署须知

  • 一个稳健的 Redis Sentinel 集群,应该使用至少三个 Sentinel 实例,并且保证讲这些实例放到 不同的机器 上,甚至不同的 物理区域
  • Sentinel 无法保证 强一致性
  • 常见的 客户端应用库 都支持 Sentinel
  • Sentinel 需要通过不断的测试观察,才能保证高可用

2、Redis Sentinel 节点规划

服务类型 主从复制 IP Port
Redis Master 192.168.182.11 16379
Redis slave - 1 192.168.182.11 26379
Redis slave - 2 192.168.182.11 36379
Sentinel - 192.168.182.11 16380
Sentinel - 192.168.182.11 26380
Sentinel - 192.168.182.11 36380

3、Redis-Server (主从复制)配置部署

  • 分别在/usr/local/bin/sentinel目录下创建 sentinel-1sentinel-2sentinel-3 文件夹
[root@localhost sentinel]# mkdir sentinel-1 sentinel-2 sentinel-3
[root@localhost sentinel]# ls
sentinel-1  sentinel-2  sentinel-3
  • redis.conf 配置文件分别拷贝至 sentinel-1sentinel-2sentinel-3 文件夹下
[root@localhost bin]# cp redis.conf sentinel/sentinel-1
[root@localhost bin]# cp redis.conf sentinel/sentinel-2
[root@localhost bin]# cp redis.conf sentinel/sentinel-3

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

PS:配置文件务必要按顺序修改,否则会报错无法识别master

  • 主节点: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 ./redis-workdir
masterauth 123456
requirepass 123456
  • 从节点1: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 ./redis-workdir
masterauth 123456
requirepass 123456
slaveof 127.0.0.1 16379
  • 从节点2: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 ./redis-workdir
masterauth 123456
requirepass 123456
slaveof 127.0.0.1 16379

PS:如果要做自动故障转移,建议所有的 redis.conf 都设置 masterauth。因为自动故障只会重写主从关系,即slaveof,不会自动写入 masterauth。如果 Redis 原本没有设置密码,则可以忽略。

Redis-Server启动验证

  • 按顺序分别启动redis-1、redis-2、redis-3节点
[root@localhost bin]# redis-server sentinel/sentinel-1/redis.conf 
[root@localhost bin]# redis-server sentinel/sentinel-2/redis.conf 
[root@localhost bin]# redis-server sentinel/sentinel-3/redis.conf 
  • 查看启动进程
root      80625      1  0 15:24 ?        00:00:17 redis-server 0.0.0.0:36379
root      80631      1  0 15:24 ?        00:00:16 redis-server 0.0.0.0:26379
root      82108      1  0 17:22 ?        00:00:01 redis-server 0.0.0.0:16379
  • 主节点redis-16379写入数据,查看从节点1:redis-26379、从节点2:redis-36379是否同步数据
127.0.0.1:16379> set mykeys redis
OK
127.0.0.1:26379> keys *
1) "mykey"
127.0.0.1:36379> keys *
1) "mykey"

主从节点数据已同步,主从复制搭建部署完成


三、Sentinel(哨兵)配置部署

  • sentinel.conf 配置文件分别拷贝至 sentinel-1sentinel-2sentinel-3 文件夹下
[root@localhost bin]# cp sentinel.conf sentinel/sentinel-1/
[root@localhost bin]# cp sentinel.conf sentinel/sentinel-2/
[root@localhost bin]# cp sentinel.conf sentinel/sentinel-3/

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

PS:配置文件务必要按顺序修改,否则会报错无法识别master

  • 节点1:sentinel-16380
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
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
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

Sentinel启动验证

  • 按顺序分别启动 16380,2638036380三个Sentinel 节点,启动命令和启动日志如下:
[root@localhost bin]# redis-server sentinel/sentinel-1/sentinel.conf --sentinel
[root@localhost bin]# redis-server sentinel/sentinel-2/sentinel.conf --sentinel
[root@localhost bin]# redis-server sentinel/sentinel-3/sentinel.conf --sentinel
  • 查看 Sentinel 的启动进程:
[root@localhost bin]# ps -ef | grep redis
root      80625      1  0 15:24 ?        00:00:18 redis-server 0.0.0.0:36379
root      80631      1  0 15:24 ?        00:00:17 redis-server 0.0.0.0:26379
root      82108      1  0 17:22 ?        00:00:04 redis-server 0.0.0.0:16379
root      82573      1  0 17:51 ?        00:00:00 redis-server 0.0.0.0:16380 [sentinel]
root      82595      1  0 17:52 ?        00:00:00 redis-server 0.0.0.0:26380 [sentinel]
root      82617      1  0 17:53 ?        00:00:00 redis-server 0.0.0.0:36380 [sentinel]

查看 Sentinel 的启动日志:

  • 节点 sentinel-16380
[root@localhost sentinel-1]# cat sentinel.log 
8166:X 12 Jan 2020 18:42:45.941 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
8166:X 12 Jan 2020 18:42:45.941 # Redis version=5.0.4, bits=64, commit=00000000, modified=0, pid=8166, just started
8166:X 12 Jan 2020 18:42:45.941 # Configuration loaded
8167:X 12 Jan 2020 18:42:45.956 * Increased maximum number of open files to 10032 (it was originally set to 1024).
8167:X 12 Jan 2020 18:42:45.957 * Running mode=sentinel, port=16380.
8167:X 12 Jan 2020 18:42:45.957 # Sentinel ID is ddf49c992bceba4fe13eb213bd72aa7db9ff101b
8167:X 12 Jan 2020 18:42:45.957 # +monitor master master 127.0.0.1 16379 quorum 2
8167:X 12 Jan 2020 18:42:48.970 # +sdown master master 127.0.0.1 16379

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

  • 节点 sentinel-26380
[root@localhost sentinel-2]# cat sentinel.log 
8180:X 12 Jan 2020 18:42:58.483 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
8180:X 12 Jan 2020 18:42:58.483 # Redis version=5.0.4, bits=64, commit=00000000, modified=0, pid=8180, just started
8180:X 12 Jan 2020 18:42:58.483 # Configuration loaded
8181:X 12 Jan 2020 18:42:58.496 * Increased maximum number of open files to 10032 (it was originally set to 1024).
8181:X 12 Jan 2020 18:42:58.496 * Running mode=sentinel, port=26380.
8181:X 12 Jan 2020 18:42:58.496 # Sentinel ID is ddf49c992bceba4fe13eb213bd72aa7db9ff101b
8181:X 12 Jan 2020 18:42:58.496 # +monitor master master 127.0.0.1 16379 quorum 2
8181:X 12 Jan 2020 18:42:58.499 * +slave slave 127.0.0.1:26379 127.0.0.1 26379 @ master 127.0.0.1 16379
8181:X 12 Jan 2020 18:42:58.500 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 16379

可以注意到,sentinel-26380.conf 刷新写入了 Redis 主节点关联的所有 从节点 redis-26379 和 redis-36379,同时写入了其余两个 Sentinel 节点 sentinel-36380 和 sentinel-16380 的 IP 地址,端口号 和 Sentinel ID。


四、哨兵故障切换

Redis Sentinel故障切换

  • kill 杀掉主节点:redis-16379 的进程
[root@localhost sentinel-1]# kill 8757
  • 查看日志(此时主节点已经切换至redis-36379
......
8801:X 12 Jan 2020 19:17:47.631 * +slave slave 127.0.0.1:26379 127.0.0.1 26379 @ master 127.0.0.1 36379
8801:X 12 Jan 2020 19:17:47.631 * +slave slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 36379
8801:X 12 Jan 2020 19:17:50.668 # +sdown slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 36379
......
127.0.0.1:26380> sentinel master master

 1) "name"
 2) "master"
 3) "ip"
 4) "127.0.0.1"
 5) "port"
 6) "36379"
 7) "runid"
 8) "15ea078acd8471bf2072a68c1c3f3fc570cb5cca"
 9) "flags"
10) "master"
127.0.0.1:16380> 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=master,status=oup,address=127.0.0.1:36379,slaves=2,sentinels=3

五、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

学习至:Redis哨兵模式与高可用集群

你可能感兴趣的:(Redis)