redis 哨兵模式

Redis Sentinel是Redis高可用性解决方案,负责监控、通知和自动故障迁移。当主节点故障时,Sentinel系统会选举新的主节点,并更新所有从节点和客户端连接。Sentinel通过不断检测节点状态,实现主观下线和客观下线判断,确保数据服务的连续性。此外,Sentinel还会自动刷新配置,确保故障转移后的正确性。
摘要由CSDN通过智能技术生成

先聊聊什么是哨兵机制?

Redis的哨兵(sentinel) 系统用于管理多个 Redis 服务器,该系统执行以下三个任务:

监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。

**提醒(Notification):**当被监控的某个 Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。

**自动故障迁移(Automatic failover):**当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其他Slave改为复制新的Master; 当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master。

1.为什么要有哨兵机制?

哨兵机制的出现是为了解决主从复制的缺点的!再这谈谈redis的主从复制的缺点:

  • 主从复制,若主节点出现问题,则不能提供服务,需要人工修改配置将从变主
  • 主从复制主节点的写能力单机,能力有限
  • 单机节点的存储能力也有限

2.哨兵机制(sentinel)的高可用

原理: 当主节点出现故障时,由Redis Sentinel自动完成故障发现和转移,并通知应用方,实现高可用性。

image.png

其实整个过程只需要一个哨兵节点来完成,首先使用Raft算法(选举算法)实现选举机制,选出一个哨兵节点来完成转移和通知

3.哨兵的定时监控任务

任务1: 每个哨兵节点每10秒会向主节点和从节点发送info命令获取最拓扑结构图,哨兵配置时只要配置对主节点的监控即可,通过向主节点发送info,获取从节点的信息,并当有新的从节点加入时可以马上感知到。

image.png

任务2: 每个哨兵节点每隔2秒会向redis数据节点的指定频道上发送该哨兵节点对于主节点的判断以及当前哨兵节点的信息,同时每个哨兵节点也会订阅该频道,来了解其它哨兵节点的信息及对主节点的判断,其实就是通过消息publish和subscribe来完成的。

image.png

任务3: 每隔1秒每个哨兵会向主节点、从节点及其余哨兵节点发送一次ping命令做一次心跳检测,这个也是哨兵用来判断节点是否正常的重要依据。

客观下线: 当主观下线的节点是主节点时,此时该哨兵3节点会通过指令sentinel is-masterdown-by-addr寻求其它哨兵节点对主节点的判断,当超过quorum(选举)个数,此时哨兵节点则认为该主节点确实有问题,这样就客观下线了,大部分哨兵节点都同意下线操作,也就说是客观下线。

4.领导者哨兵选举流程

  • 每个在线的哨兵节点都可以成为领导者,当它确认(比如哨兵3)主节点下线时,会向其它哨兵发is-master-down-by-addr命令,征求判断并要求将自己设置为领导者,由领导者处理故障转移;
  • 当其它哨兵收到此命令时,可以同意或者拒绝它成为领导者;
  • 如果哨兵3发现自己在选举的票数大于等于num(sentinels)/2+1时,将成为领导者,如果没有超过,继续选举…………

5.故障转移机制

由Sentinel节点定期监控发现主节点是否出现了故障: sentinel会向master发送心跳PING来确认master是否存活,如果master在“一定时间范围”内不回应PONG 或者是回复了一个错误消息,那么这个sentinel会主观地(单方面地)认为这个master已经不可用了

image.png

当主节点出现故障, 此时3个Sentinel节点共同选举了Sentinel3节点为领导,负载处理主节点的故障转移

image.png

由Sentinel3领导者节点执行故障转移,过程和主从复制一样,但是自动执行

image.png

流程:

  1. 将slave-1脱离原从节点,升级主节点,
  2. 将从节点slave-2指向新的主节点
  3. 通知客户端主节点已更换
  4. 将原主节点(oldMaster)变成从节点,指向新的主节点

故障转移后的redis sentinel的拓扑结构图

5.哨兵机制-故障转移详细流程-确认主节点

  • 过滤掉不健康的(下线或断线),没有回复过哨兵ping响应的从节点
  • 选择salve-priority从节点优先级最高(redis.conf)的
  • 选择复制偏移量最大,此指复制最完整的从节点

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 SentinelRedis高可用实现方案Sentinel节点集合和Redis数据节点进程
应用客户端泛指一个或多个客户端一个或者多个客户端进程或者线程

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

Redis主从复制的问题

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

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

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

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

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

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

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

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 主节点从节点 交互的命令,主要包括:

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

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

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

4.5. Redis Sentinel的工作原理

每个 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 Master10.206.20.23116379
Redis Slave110.206.20.23126379
Redis Slave210.206.20.23136379
Redis Sentinel110.206.20.23116380
Redis Sentinel210.206.20.23126380
Redis Sentinel310.206.20.23136380

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
复制代码

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

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
复制代码

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
复制代码

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 的启动日志:

$ 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
复制代码

$ 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
复制代码

$ 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
复制代码

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
复制代码

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
复制代码

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 的启动日志:

$ 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 集群中。

$ 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 两个节点。

$ 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配置刷新

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时客户端命令

> 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 failover <master_name>

> SENTINEL reset <pattern>
复制代码
  • 每个 Sentinel每秒钟 一次的频率,向它所知的 主服务器从服务器 以及其他 Sentinel 实例 发送一个 PING 命令。如果一个 实例instance)距离 最后一次 有效回复 PING 命令的时间超过 down-after-milliseconds 所指定的值,那么这个实例会被 Sentinel 标记为 主观下线
  • 如果一个 实例instance)距离 最后一次 有效回复 PING 命令的时间超过 down-after-milliseconds 所指定的值,那么这个实例会被 Sentinel 标记为 主观下线
  • 如果一个 主服务器 被标记为 主观下线,那么正在 监视 这个 主服务器 的所有 Sentinel 节点,要以 每秒一次 的频率确认 主服务器 的确进入了 主观下线 状态。
  • 如果一个 主服务器 被标记为 主观下线,并且有 足够数量 的 Sentinel(至少要达到 配置文件 指定的数量)在指定的 时间范围 内同意这一判断,那么这个 主服务器 被标记为 客观下线
  • 在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率,向它已知的所有 主服务器从服务器 发送 INFO 命令。当一个 主服务器Sentinel 标记为 客观下线 时,Sentinel下线主服务器 的所有 从服务器 发送 INFO 命令的频率,会从 10 秒一次改为 每秒一次

  • Sentinel 和其他 Sentinel 协商 主节点 的状态,如果 主节点 处于 SDOWN 状态,则投票自动选出新的 主节点。将剩余的 从节点 指向 新的主节点 进行 数据复制
  • 当没有足够数量的 Sentinel 同意 主服务器 下线时, 主服务器 的 客观下线状态 就会被移除。当 主服务器 重新向 Sentinel 的 PING 命令返回 有效回复 时,主服务器 的 主观下线状态 就会被移除。
  • 一个有效的 PING 回复可以是:+PONG-LOADING 或者 -MASTERDOWN。如果 服务器 返回除以上三种回复之外的其他回复,又或者在 指定时间 内没有回复 PING 命令, 那么 Sentinel 认为服务器返回的回复 无效non-valid)。

    Redis Sentinel搭建

    5.1. Redis Sentinel的部署须知

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

  • Sentinel 无法保证 强一致性

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

  • Sentinel 需要通过不断的 测试观察,才能保证高可用。

  • 主节点:redis-16379.conf
  • 从节点1:redis-26379.conf
  • 从节点2:redis-36379.conf
  • 节点 redis-16379
  • 节点 redis-26379
  • 节点 redis-36379
  • 节点1:sentinel-16380.conf
  • 节点2:sentinel-26380.conf
  • 节点3:sentinel-36380.conf
  • 节点 sentinel-16380
  • 节点 sentinel-26380
  • 节点 sentinel-36380
  • 节点1:sentinel-16380.conf
  • 检查其他 Sentinel 节点的状态,返回 PONG 为正常。
  • 显示被监控的所有 主节点 以及它们的状态。
  • 显示指定 主节点 的信息和状态。
  • 显示指定 主节点 的所有 从节点 以及它们的状态。
  • 重置名字匹配该 正则表达式 的所有的 主节点 的状态信息,清除它之前的 状态信息,以及 从节点 的信息。
  • 强制当前 Sentinel 节点执行 failover,并且不需要得到其他 Sentinel 节点的同意。但是 failover 后会将 最新的配置 发送给其他 Sentinel 节点。

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 集群模式 予以解决。


作者:零壹技术栈
链接:https://juejin.cn/post/6844903663362637832
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值