Redis 哨兵模式

哨兵简介

Redis 哨兵(Sentinel)是 Redis 的高可用性(Hight Availability)解决方案:由一个或多个 Sentinel 实例组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。

Sentinel 本质上是一个运行在特殊状模式下的 Redis 服务器

img

Sentinel 的主要功能如下:

  • 监控(Monitoring) - Sentinel 不断检查主从服务器是否正常在工作。
  • 通知(Notification) - Sentinel 可以通过一个 api 来通知系统管理员或者另外的应用程序,被监控的 Redis 实例有一些问题。
  • 自动故障转移(Automatic Failover) - 如果一个主服务器下线,Sentinel 会开始自动故障转移:把一个从节点提升为主节点,并重新配置其他的从节点使用新的主节点,使用 Redis 服务的应用程序在连接的时候也被通知新的地址。
  • 配置提供者(Configuration provider) - Sentinel 给客户端的服务发现提供来源:对于一个给定的服务,客户端连接到 Sentinels 来寻找当前主节点的地址。当故障转移发生的时候,Sentinel 将报告新的地址。

监控

检测服务器状态

Sentinel 向 Redis 服务器发送 PING 命令,检查其状态

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

  • 主观下线主观下线 适用于所有 主节点从节点。如果在 down-after-milliseconds 毫秒内,Sentinel 没有收到 目标节点 的有效回复,则会判定 该节点主观下线
  • 客观下线客观下线 只适用于 主节点。当 Sentinel 将一个主服务器判断为主管下线后,为了确认这个主服务器是否真的下线,会向同样监视这一主服务器的其他 Sentinel 询问,看它们是否也认为主服务器已经下线。当足够数量的 Sentinel 认为主服务器已下线,就判定其为客观下线,并对其执行故障转移操作。
    • Sentinel 节点通过 sentinel is-master-down-by-addr 命令,向其它 Sentinel 节点询问对该节点的 状态判断

获取服务器信息

Sentinel 向主服务器发送 INFO 命令,获取主服务器及它的从服务器信息

  • 获取主服务器信息 - Sentinel 默认会以每十秒一次的频率,通过命令连接向被监视的主服务器发送 INFO 命令,并通过分析 INFO 命令的回复来获取主服务器的当前信息
    • 主服务自身信息:包括 run_id 域记录的服务器运行 ID,以及 role 域记录的服务器角色
    • 主服务的从服务器信息:包括 IP 地址和端口号
  • 获取从服务器信息 - 当 Sentinel 发现主服务器有新的从服务器出现时,Sentinel 除了会为这个新的从服务器创建相应的实例结构之外,Sentinel 还会创建连接到从服务器的命令连接和订阅连接。

命令

  • PING: 返回 PONG 。
  • SENTINEL masters: 列出所有被监视的主服务器,以及这些主服务器的当前状态;
  • SENTINEL slaves <master name>: 列出给定主服务器的所有从服务器,以及这些从服务器的当前状态;
  • SENTINEL get-master-addr-by-name <master name>: 返回给定名字的主服务器的 IP 地址和端口号。 如果这个主服务器正在执行故障转移操作, 或者针对这个主服务器的故障转移操作已经完成, 那么这个命令返回新的主服务器的 IP 地址和端口号;
  • SENTINEL reset <pattern>: 重置所有名字和给定模式 pattern 相匹配的主服务器。 pattern 参数是一个 Glob 风格的模式。 重置操作清楚主服务器目前的所有状态, 包括正在执行中的故障转移, 并移除目前已经发现和关联的, 主服务器的所有从服务器和 Sentinel ;
  • SENTINEL failover <master name>: 当主服务器失效时, 在不询问其他 Sentinel 意见的情况下, 强制开始一次自动故障迁移。 (不过发起故障转移的 Sentinel 会向其他 Sentinel 发送一个新的配置,其他 Sentinel 会根据这个配置进行相应的更新)
  • SENTINEL MONITOR <name> <ip> <port> <quorum>: 这个命令告诉sentinel去监听一个新的master
  • SENTINEL REMOVE <name>: 命令sentinel放弃对某个master的监听
  • SENTINEL SET <name> <option> <value>: 这个命令很像Redis的CONFIG SET命令,用来改变指定master的配置。支持多个

通知

对于每个与 Sentinel 连接的服务器,Sentinel 既会向服务器的 __sentinel__:hello 频道发送消息,也会订阅服务器的 __sentinel__:hello 频道的消息。

向服务器发送消息

在默认情况下,Sentinel 会以每两秒一次的频率,通过命令向所有被监视的主服务器和从服务器发送以下格式的命令。

1
PUBLISH __sentinel__:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"

这条命令向服务器的 __sentinel__:hello 频道发送一条消息。

接收服务器的消息

当 Sentinel 与一个主服务器或从服务器建立起订阅连接后,Sentinel 就会通过订阅连接,向服务器发送以下命令:SUBSCRIBE __sentinel__:hello

Sentinel 对 __sentinel__:hello 频道的订阅会一直持续到 Sentinel 与服务器断开连接为止。

选举 Leader

Redis Sentinel 系统选举 Leader 的算法是 Raft 的实现。

当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个 Sentinel 会进行协商,选举出一个领头的 Sentinel,并由领头 Sentinel 对下线主服务器执行故障转移操作

所有在线 Sentinel 都有资格被选为 Leader。

每个 Sentinel 节点都需要 定期执行 以下任务:

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

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

六、故障转移

在选举产生出 Sentinel Leader 后,Sentinel Leader 将对已下线的主服务器执行故障转移操作。操作含以下三个步骤:

(一)选出新的主服务器

故障转移第一步,是 Sentinel Leader 在已下线主服务属下的所有从服务器中,挑选一个状态良好、数据完整的从服务器。然后,向这个从服务器发送 SLAVEOF no one 命令,将其转换为主服务器。

Sentinel Leader 如何选出新的主服务器:

  • 删除列表中所有处于下线或断线状态的从服务器。
  • 删除列表中所有最近五秒没有回复过 Sentinel Leader 的 INFO 命令的从服务器。
  • 删除所有与已下线主服务器连接断开超过 down-after-milliseconds * 10 毫秒的从服务器(down-after-milliseconds 指定了判断主服务器下线所需的时间)。
  • 之后, Sentinel Leader 先选出优先级最高的从服务器;如果优先级一样高,再选择复制偏移量最大的从服务器;如果结果还不唯一,则选出运行 ID 最小的从服务器。

(二)修改从服务器的复制目标

选出新的主服务器后,Sentinel Leader 会向所有从服务器发送 SLAVEOF 命令,让它们去复制新的主服务器。

(三)将旧的主服务器变为从服务器

Sentinel Leader 将旧的主服务器标记为从服务器。当旧的主服务器重新上线,Sentinel 会向它发送 SLAVEOF 命令,让其成为从服务器。

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# Example sentinel.conf

# 关闭安全模式
protected-mode no

# 哨兵模式使用的端口
port 26379

# 后台启动
daemonize yes

# 后台启动后存放的PID
pidfile /var/run/redis-sentinel.pid

# 日志文件
logfile ""


# 指定 Sentinel 使用的端口和IP,不需要同时使用。
# sentinel announce-ip <ip>
# sentinel announce-port <port>

# 工作目录
dir /tmp

# 哨兵 sentinel 监控的 redis 主节点 ip port
# master-name 可以自己命名的主节点名字 只能由字母 A-Z 数字0-9 这三个字符".-_" 组成
# quorum 配置多少个 sentinel 哨兵统一认为 master主节点失联, 那么这时候客观上认为主节点失联了
sentinel monitor mymaster 127.0.0.1 6379 2

# 当Redia实例中开启了 requirepass foobared 授权密码 这样所有的连接Redis 实例的客户端都要提供密码
# 设置哨兵 sentinel 连接主从密码, 注意必须为主从设置一样的验证密码
# sentinel auth-pass mymaster MySUPER--secret-0123passw0rd

# 同上,高版本使用了用户名密码的方式
# sentinel auth-user <master-name> <username>

# 指定多少毫秒之后, 主节点没有应答哨兵 sentinel 此时 哨兵主管上认为节点下线 默认 30s
sentinel down-after-milliseconds mymaster 30000

# ACL LOG
#
# ACL日志认证失败的最大存储长度,方还在内存里面
acllog-max-len 128

# 使用外部的ACL日志认证文件
# aclfile /etc/redis/sentinel-users.acl

# Sentinel 链接使用的密码
# requirepass <password>
# sentinel sentinel-user <username>
# sentinel sentinel-pass <password>


# 这个配置项指定了发生 failover 主备切换时最多有多少个slave同时对新的master 进行同步
# 这个数字越小 完成 failover 所需时间就越长
# 但是如果这个数字越大, 就意味着越多的 slave 因为 replication而不可用
# 可以通过这个值设置为1 来保证每次只有一个 slave 处于不能处理命令的请求状态
sentinel parallel-syncs mymaster 1

# 故障转移超时时间 failover-timeout 可以用在以下这些方面
# 1 同一个 sentinel 对同一个master两次 failover 之间的间隔时间
# 2 一个 slave 从一个错误的 master 那里同步数据开始计算时间, 直到 slave 被纠正为正确的 master 那里同步数据时
# 3 当想要取消一个正在进行的 failover 所需要的时间
# 4 当进行 failover 时, 配置所有 slaves 指定新的 master 所需要的最大时间. 不过, 即使过了这个超时, slave 依然会被正确的配置为指向 master 但是就不按 paralle1- syncs 所配置规来了
sentinel failover-timeout mymaster 180000

# SCRIPTS EXECUTION

# 配置当某一件事情发生时, 所需要执行的脚本, 可以通过脚本通知来通知管理员, 例如当系统不能正常发邮件通知相关人员
# 对于脚本的运行结果有以下规则
# 若脚本执行后返回1, 那么该脚本稍后将会被再次执行, 重复次数默认为 10
# 若脚本执行后返回2, 或者比2更高的一个返回值, 脚本将不会重复执行
# 如果脚本在执行过程中由于收到系统中断信号被终止了, 则同返回值1时的行为相同
# 一个脚本的最大执行时间为60s, 如果超过了这个时间, 脚本将会被一个SIGKILL信号终止, 之后重新执行
# sentinel notification-script mymaster /var/redis/notify.sh

# CLIENTS RECONFIGURATION SCRIPT
#
# sentinel 重新配置
# sentinel client-reconfig-script <master-name> <script-path>
# sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

# SECURITY
#
# 避免脚本重置
sentinel deny-scripts-reconfig yes

# REDIS COMMANDS RENAMING
# sentinel 命令重命名
# SENTINEL rename-command mymaster CONFIG GUESSME
# SENTINEL rename-command mymaster CONFIG CONFIG

# HOSTNAMES SUPPORT

SENTINEL resolve-hostnames no
SENTINEL announce-hostnames no