Redis 系列 6. Sentinel 哨兵高可用机制


1. Sentinel 是什么

上一篇讲了 Redis 主从复制。普通主从有一个明显问题:master 宕机后,replica 不会自动升级为新 master。

Redis Sentinel 是 Redis 的分布式监控与故障转移系统。它持续监控 master、replica 和其他 Sentinel 的状态。如果 master 被判断为不可用,Sentinel 会自动完成故障转移,把某个 replica 提升为新的 master,并让其他 replica 改为复制新 master。

这里可以先明确一点:Sentinel 是支撑 Redis 自动化故障转移的核心组件。

2. Sentinel 能做什么

Sentinel 主要提供四类能力:

能力 说明
监控 持续检查 master、replica、其他 Sentinel 是否正常
通知 发现故障或切换后,可以向客户端或脚本通知
自动故障转移 master 异常时,选择 replica 晋升为新 master
配置中心 客户端可以通过 Sentinel 获取当前 master 地址

注意:Sentinel 本身不存业务数据,它只负责监控、选举和切换。但 Sentinel 会持久化监控状态和拓扑变更,因此 sentinel.conf 不是纯静态配置文件。

3. 实验架构

一个典型 Sentinel 实验环境:

组件 数量 说明
master 1 负责写
replica 2 从 master 复制数据
sentinel 3 监控主从并负责故障转移

Redis Sentinel 架构

生产上 Sentinel 应该分布在不同机器上。学习环境可以把 3 个 Sentinel 放在一台机器的不同端口,但这不能代表真正高可用。

4. Sentinel 配置文件

假设 master 地址是 192.168.10.101:6379,密码是 111111,新建:

/myredis/sentinel26379.conf
/myredis/sentinel26380.conf
/myredis/sentinel26381.conf

以 sentinel26379.conf 为例:

bind 0.0.0.0
protected-mode no
port 26379
daemonize yes
logfile "/myredis/sentinel26379.log"
pidfile /var/run/redis-sentinel26379.pid
dir /myredis

sentinel monitor mymaster 192.168.10.101 6379 2
sentinel auth-pass mymaster 111111
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 60000

这里容易写错成 sentinei monitor,实际应该是:

sentinel monitor mymaster 192.168.10.101 6379 2

关键参数说明:

参数 说明
mymaster 给被监控 master 起的逻辑名
192.168.10.101 6379 master 地址和端口
2 quorum,至少几个 Sentinel 同意才认为 master 客观下线
auth-pass Sentinel 连接 master/replica 使用的密码
down-after-milliseconds 多久无有效响应后认为主观下线
parallel-syncs 故障转移后允许几个 replica 同步新 master
failover-timeout 故障转移超时时间

quorum 只决定多少个 Sentinel 同意后可以进入客观下线判断,它不等于故障转移已经开始。真正执行 failover 之前,还需要 Sentinel 之间完成 Leader 选举,并获得本轮故障转移的授权。

down-after-milliseconds 会影响 SDOWN 判定敏感度。配置太小容易因为短暂网络抖动误判;配置太大则会拉长故障发现时间。

如果 Redis 节点后续可能会被 Sentinel 配置成 replica,需要提前配置 masterauth:

# 主机 6379
# 如果 master 设置了密码,replica 在同步前需要先进行认证。
# 否则 master 会拒绝 replica 的同步请求。
# masterauth <master-password>
# 设置访问 master 的密码
# 这里的密码需要和 master 的 requirepass 保持一致
masterauth "111111"

当它作为 replica 去连接新的 master 时,会使用 masterauth 中配置的密码进行认证。如果 master 设置了访问密码,而 replica 没有配置 masterauth,主从复制可能会失败,并出现类似状态:

master_link_status:down

所以在主从复制环境中,如果主节点配置了 requirepass 111111,从节点一般也需要配置 masterauth “111111”。如果使用 Redis 6 及以上版本,生产环境更推荐使用 ACL 管理复制用户和客户端用户,而不是所有组件共享一个密码。

5. 启动 Sentinel

先启动 Redis 一主二从,并确认复制关系正常:

redis-cli -p 6379 --pass 111111 info replication
redis-cli -p 6380 --pass 111111 info replication
redis-cli -p 6381 --pass 111111 info replication

再启动 3 个 Sentinel:

redis-sentinel /myredis/sentinel26379.conf
redis-sentinel /myredis/sentinel26380.conf
redis-sentinel /myredis/sentinel26381.conf

也可以使用:

redis-server /myredis/sentinel26379.conf --sentinel
# Sentinel 启动
[root@hadoop100 ~]# redis-sentinel /myredis/sentinel26379.conf
[root@hadoop100 ~]# redis-sentinel /myredis/sentinel26380.conf
[root@hadoop100 ~]# redis-sentinel /myredis/sentinel26381.conf

6. 查看 Sentinel 状态

连接 Sentinel:

redis-cli -p 26379

查看 master:

sentinel masters

查看指定 master:

sentinel master mymaster

查看 replica:

sentinel replicas mymaster

查看其他 Sentinel:

sentinel sentinels mymaster

获取当前 master 地址:

sentinel get-master-addr-by-name mymaster

应用客户端通常就是通过 Sentinel 获取当前 master,而不是把 master IP 写死。

7. 模拟 master 故障

手动关闭 master:

redis-cli -p 6379 --pass 111111 shutdown

Sentinel 会经历:

  1. 某个 Sentinel 先认为 master 主观下线。
  2. 多个 Sentinel 达成一致,认为 master 客观下线。
  3. Sentinel 之间选出 Leader。
  4. Leader Sentinel 选择一个 replica 晋升为新 master。
  5. 其他 replica 改为复制新 master。
  6. 旧 master 恢复后,会被改造成新 master 的 replica。

这里的切换由 Leader Sentinel 执行,不是所有 Sentinel 同时对 Redis 节点下发切换命令。

故障切换后,可以通过 INFO replication 观察角色变化:

127.0.0.1:6381> info replication                         # 查看 6381 节点的主从复制信息
# Replication
role:master                                              # 当前 6381 节点已经成为 master,说明发生了主从切换/上位
connected_slaves:1                                       # 当前 master 下连接了 1 个从库
slave0:ip=192.168.10.102,port=6380,state=online,offset=103602,lag=1
                                                           # 从库信息:IP 为 192.168.10.102,端口 6380,状态 online
master_failover_state:no-failover                        # 当前没有正在进行的故障转移
master_replid:1467fce583a04419127f0c99dda1f4a0f4c5e8c0
master_replid2:1cdd22a0fd4fb6b5a7b5c7783e4314f814e9a877
master_repl_offset:103888                                # 当前 master 的复制偏移量
second_repl_offset:90197
repl_backlog_active:1                                    # 复制积压缓冲区已开启
repl_backlog_size:1048576                                # 复制积压缓冲区大小,默认约 1MB
repl_backlog_first_byte_offset:43
repl_backlog_histlen:103846                              # 当前复制积压缓冲区中保存的数据长度

127.0.0.1:6380> info replication                         # 查看 6380 节点的主从复制信息
# Replication
role:slave                                               # 当前 6380 节点是 slave,从属于新的 master
master_host:192.168.10.103                               # 当前从库连接的 master 地址是 192.168.10.103
master_port:6381                                         # 当前从库连接的 master 端口是 6381
master_link_status:up                                    # 主从连接状态正常
master_last_io_seconds_ago:0                             # 距离上次和 master 通信过去 0 秒
master_sync_in_progress:0                                # 当前没有正在进行全量同步
slave_read_repl_offset:102301                            # 从库读取到的复制偏移量
slave_repl_offset:102301                                 # 从库当前复制偏移量
slave_priority:100                                       # 从库优先级,哨兵选主时会参考该值
slave_read_only:1                                        # 从库只读
replica_announced:1                                      # 当前 replica 会被正常通告
connected_slaves:0                                       # 当前从库下面没有再挂其他从库
master_failover_state:no-failover                        # 当前没有正在进行故障转移
master_replid:1467fce583a04419127f0c99dda1f4a0f4c5e8c0
master_replid2:1cdd22a0fd4fb6b5a7b5c7783e4314f814e9a877
master_repl_offset:102301
second_repl_offset:90197
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:102287

6381 已经上位成为新的 master,而 6380 已经变成它的从库,并且 master_link_status:up 表示主从复制链路正常。

127.0.0.1:6379> info replication                         # 查看 6379 节点的主从复制信息
Error: Server closed the connection                       # Redis 服务端关闭了连接,通常表示当前连接的节点重启或连接中断

not connected> info replication                           # 当前 redis-cli 还没有重新连接成功
# Replication
role:slave                                                # 当前 6379 节点已经变成从节点
master_host:192.168.10.103                                # 当前从属于新的 master,master IP 为 192.168.10.103
master_port:6381                                          # 新 master 的端口是 6381
master_link_status:up                                     # 主从复制链路正常
master_last_io_seconds_ago:0                              # 距离上次和 master 通信过去 0 秒
master_sync_in_progress:0                                 # 当前没有正在进行全量同步
slave_read_repl_offset:146834                             # 从节点已读取的复制偏移量
slave_repl_offset:146834                                  # 从节点当前复制偏移量
slave_priority:100                                        # 从节点优先级,哨兵选主时会参考该值
slave_read_only:1                                         # 从节点只读
replica_announced:1                                       # 当前 replica 会被正常通告
connected_slaves:0                                        # 当前节点下面没有其他从节点
master_failover_state:no-failover                         # 当前没有正在进行故障转移
master_replid:1467fce583a04419127f0c99dda1f4a0f4c5e8c0     # 当前 master 的复制 ID
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:146834                                 # 当前 master 的复制偏移量
second_repl_offset:-1
repl_backlog_active:1                                     # 复制积压缓冲区已开启
repl_backlog_size:1048576                                 # 复制积压缓冲区大小,约 1MB
repl_backlog_first_byte_offset:128096
repl_backlog_histlen:18739
# Sentinel 日志:主节点 192.168.10.101:6379 宕机后,哨兵开始故障转移

3915:X * +sentinel sentinel 75cda70eb27d0f071b1c2f82fe76b2fd7af2efa3 192.168.10.101 26381 @ mymaster 192.168.10.101 6379
3915:X * Sentinel new configuration saved on disk

3915:X # +sdown master mymaster 192.168.10.101 6379
# sdown:主观下线。当前 Sentinel 认为 master 192.168.10.101:6379 已经不可用。

3915:X * Sentinel new configuration saved on disk
3915:X # +new-epoch 1
# 开始新的故障转移纪元 epoch,用于标识一次新的选举 / 故障转移过程。

3915:X * Sentinel new configuration saved on disk

3915:X # +vote-for-leader 57b67e7ae0dd18f15af247aee7068ebe3c8b027c 1
# Sentinel 投票选举 leader,由 leader 负责执行后续 failover。

3915:X # +odown master mymaster 192.168.10.101 6379 #quorum 2/2
# odown:客观下线。达到 quorum 票数,确认 master 真的下线。

3915:X # Next failover delay: the next failover will not start before the configured retry time
# 设置下一次故障转移的最早时间,避免频繁触发 failover。

3915:X # +config-update-from sentinel 57b67e7ae0dd18f15af247aee7068ebe3c8b027c 192.168.10.101 26380 @ mymaster 192.168.10.101 6379
# 从其他 Sentinel 接收到新的配置更新。

3915:X # +switch-master mymaster 192.168.10.101 6379 192.168.10.103 6381
# 主从切换完成:原 master 是 192.168.10.101:6379,新 master 变为 192.168.10.103:6381。

3915:X * +slave slave 192.168.10.102:6380 192.168.10.102 6380 @ mymaster 192.168.10.103 6381
# 6380 节点成为新 master 6381 的从节点。

3915:X * +slave slave 192.168.10.101:6379 192.168.10.101 6379 @ mymaster 192.168.10.103 6381
# 原来的 master 6379 被记录为新 master 6381 的从节点。

3915:X * Sentinel new configuration saved on disk

3915:X # +sdown slave 192.168.10.101:6379 192.168.10.101 6379 @ mymaster 192.168.10.103 6381
# 原 master 6379 作为从节点时仍然处于主观下线状态。

3915:X # -sdown slave 192.168.10.101:6379 192.168.10.101 6379 @ mymaster 192.168.10.103 6381
# 6379 节点恢复连接,取消主观下线状态。

3915:X * +convert-to-slave slave 192.168.10.101:6379 192.168.10.101 6379 @ mymaster 192.168.10.103 6381
# 6379 重启恢复后,被转换为新 master 6381 的从节点。

8. 配置文件会被 Sentinel 改写

Sentinel 运行期间会动态改写自己的配置文件。故障转移后,Redis 主从配置也可能出现变化。

常见变化:

  1. Sentinel 配置里的 master 地址变为新 master。
  2. 原 master 恢复后,可能被写入 replicaof 配置。
  3. replica 指向新 master。

所以不要把 Sentinel 配置文件当成完全静态文件。它更接近运行态配置快照,排查时要以 Sentinel 当前状态、Redis INFO replication 和配置文件共同判断。

客户端也不应该硬编码 master 地址。正确做法是通过 Sentinel 客户端协议或命令查询当前 master:

sentinel get-master-addr-by-name mymaster

9. SDown 主观下线

SDown,全称 Subjectively Down,表示某一个 Sentinel 从自己的视角判断 Redis 节点不可用。

触发条件大致是:Sentinel 给 master、replica 或其他 Sentinel 发送 PING,在 down-after-milliseconds 时间内没有收到有效响应,就会主观判断下线。

配置示例:

sentinel down-after-milliseconds mymaster 5000

可能原因包括:

  • Sentinel 收不到 Redis 服务的响应;
  • Sentinel 与 Redis 服务之间网络不通;
  • Redis 服务没有在规定时间内回复 PING;
  • Redis 服务返回了错误响应。

完整配置格式如下:

# sentinel down-after-milliseconds <master-name> <milliseconds>
# Number of milliseconds the master (or any attached replica or sentinel) should
# be unreachable, as in, not acceptable reply to PING, continuously, for the
# specified period in order to consider it in S_DOWN state (Subjectively Down).
# Default is 30 seconds.
sentinel down-after-milliseconds mymaster 30000

主观下线只是单个 Sentinel 的判断,不能直接触发故障转移。它需要通过 Sentinel 之间的消息交换,进一步形成客观下线判断。

10. ODown 客观下线

ODown,全称 Objectively Down,表示多个 Sentinel 达成一致,认为 master 确实不可用。它依赖 Sentinel 之间交换故障判断结果,本质上是从“单点视角”升级为“多数视角”。

sentinel monitor 最后的数字就是 quorum:

sentinel monitor mymaster 192.168.10.101 6379 2

这里的 2 表示至少 2 个 Sentinel 同意 master 下线,才会进入客观下线判断。

需要注意,quorum 用来确认 ODown;真正执行故障转移时,还需要 Sentinel 之间完成 Leader 选举,并获得足够的投票授权。也就是说:

SDOWN = 单个 Sentinel 的判断
ODOWN = 达到 quorum 后的下线判断
failover = ODOWN + Leader election + failover 执行

11. Leader Sentinel 选举

当 master 被判定为客观下线后,Sentinel 之间会选举一个 Leader Sentinel 来负责本次故障转移。

可以理解为:不是所有 Sentinel 同时去切换,而是选一个负责人执行切换流程。

这个过程使用类似 Raft 的 leader election 思想,但 Sentinel 不是完整的 Raft 实现。每个 Sentinel 在同一个 epoch 中只能投给一个候选者,获得足够票数的 Sentinel 成为 Leader。

epoch 用来标识一轮故障转移和投票过程,避免多个 Sentinel 在同一轮中重复授权。Leader Sentinel 是一次故障转移的执行者,负责选择新 master、发起晋升,并调整其他 replica 的复制关系。

12. 新 master 如何选择

Leader Sentinel 会在 replica 中选择一个晋升为新 master。

选择时大致按下面规则排序:

  1. 优先选择 replica-priority 数值更小的 replica,0 表示永久不参与晋升。
  2. 如果优先级相同,选择复制 offset 最大的 replica,说明它同步的数据更多,能够尽量减少故障切换后的数据丢失。
  3. 如果 offset 也相同,选择 runid 字典序更小的 replica。

配置项:

replica-priority 100

如果设置为:

replica-priority 0

表示该 replica 不参与晋升。

新 master 选择规则

13. Sentinel 故障转移完整流程

当 Redis 主节点宕机后,Sentinel 会自动完成故障转移,也就是从原来的从节点中选出一个新的主节点,并重新调整主从关系。

一次完整的故障转移大致可以分为三步。

13.1 选出新的 Master

当 Sentinel 判断原来的 master 已经不可用后,会从多个 replica 中选择一个合适的节点作为新的 master。

选中之后,Leader Sentinel 会对这个 replica 执行:

replicaof no one

旧版本命令写法是:

slaveof no one

这条命令的作用是让当前 replica 取消复制关系,不再作为从节点,而是升级为新的 master。

这里要注意,replicaof no one 只是让 Redis 节点解除复制关系并具备 master 角色。对外可写还依赖客户端已经发现新 master,并且旧 master 不再继续被写入。

简单理解:

原来的从节点不再跟随别人,自己变成新的主节点。

13.2 让其他从节点复制新的 Master

新的 master 选出来以后,Sentinel 会重新配置其他 replica,让它们不要再复制旧 master,而是改为复制新的 master。

执行的命令类似于:

replicaof new-master-ip new-master-port

旧版本命令写法是:

slaveof new-master-ip new-master-port

例如新的 master 是 192.168.10.103:6381,那么其他从节点会被重新配置为:

replicaof 192.168.10.103 6381

这样,整个主从结构就会重新恢复成:

新 master
   ↓
其他 replica

如果原来存在链式复制,故障转移后复制树也可能被重构。排查时不要只看单个节点角色,要把新 master、所有 replica 和 Sentinel 视角一起核对。

13.3 旧 Master 恢复后变成 Replica

如果原来的 master 后续重新启动,Sentinel 不会让它重新抢回 master 角色。

因为此时集群中已经有了新的 master,所以旧 master 恢复后,会被 Sentinel 自动配置成新 master 的 replica。

也就是说,旧 master 恢复后会执行类似下面的命令:

replicaof new-master-ip new-master-port

例如:

replicaof 192.168.10.103 6381

这样旧 master 就会变成新 master 的从节点,继续从新的 master 同步数据。

在网络分区或旧 master 恢复较慢的场景下,可能短时间出现客户端仍写旧 master、Sentinel 已切到新 master 的风险。这类 split-brain 风险需要靠客户端正确接入 Sentinel、网络隔离策略、min-replicas-to-write 等配置共同降低。

13.4 流程总结

Sentinel 故障转移的过程可以简单理解为:

原 master 宕机
    ↓
Sentinel 判断主观下线和客观下线
    ↓
Sentinel 选举 Leader
    ↓
Leader Sentinel 从 replica 中选出新的 master
    ↓
让新的 master 执行 replicaof no one
    ↓
让其他 replica 复制新的 master
    ↓
旧 master 恢复后,也变成新 master 的 replica

可以概括为:Sentinel 故障转移的核心是选新主、重配复制关系、让旧主重新归队。

14. Sentinel 是否保证数据零丢失

不保证。

原因是 Redis 主从复制默认是异步的。master 写入成功但还没同步给 replica 时,如果 master 宕机,这部分数据就可能丢失。

可以用下面配置降低风险:

min-replicas-to-write 1
min-replicas-max-lag 10

含义是:master 至少要有 1 个延迟不超过 10 秒的 replica,否则拒绝写入。

但这仍然不是强一致。min-replicas-to-write 更像写安全门控,只能降低 master 在 replica 不足或延迟过高时继续写入的风险,不能保证所有已确认写入都已经复制完成。

对于绝对不能丢的数据,Redis 不应该作为唯一事实来源。

15. Sentinel 部署建议

生产上建议:

  1. Sentinel 数量使用奇数,比如 3 或 5。
  2. Sentinel 分散部署在不同机器或故障域。
  3. 各 Sentinel 配置保持一致。
  4. Redis 实例和 Sentinel 都要配置认证。
  5. 客户端通过 Sentinel 发现 master,而不是写死 master IP。
  6. 监控 Sentinel 日志和 sentinel masters 状态。
  7. 容器部署时注意端口映射和 announce 地址。
  8. Redis 6 及以上版本优先规划 ACL 用户,而不是所有组件共用一个密码。

不建议:

  1. 只部署 1 个 Sentinel。
  2. 3 个 Sentinel 全放在同一台生产机器上。
  3. 业务客户端只连固定 master 地址。
  4. 把 Sentinel 当作数据节点使用。

16. 常用排查命令

# 连接 Sentinel
redis-cli -p 26379

# 查看 master 列表
sentinel masters

# 查看指定 master
sentinel master mymaster

# 查看 replicas
sentinel replicas mymaster

# 查看其他 sentinels
sentinel sentinels mymaster

# 获取当前 master 地址
sentinel get-master-addr-by-name mymaster

# 查看 Redis 自身复制状态
redis-cli -p 6379 --pass 111111 info replication
redis-cli -p 6380 --pass 111111 info replication
redis-cli -p 6381 --pass 111111 info replication

故障排查时优先看三类信息:

  1. Sentinel 日志中是否出现 +sdown、+odown、+vote-for-leader、+switch-master。
  2. sentinel get-master-addr-by-name 返回的 master 是否符合预期。
  3. Redis 各节点 INFO replication 中角色是否正确。
  4. Sentinel 是否进入 +tilt 状态。+tilt 通常表示 Sentinel 观察到系统时间跳变或事件循环异常,此时故障判断会变得保守。

Sentinel 与 Cluster 的边界也要分清:Sentinel 解决的是单 master 复制组的自动故障转移;Cluster 还负责分片、槽位迁移和多 master 横向扩展。

17. 本文小结

Sentinel 是普通主从复制的自动故障转移方案。

核心结论如下:

  1. 主从复制只负责同步数据,Sentinel 负责监控和故障转移。
  2. SDown 是单个 Sentinel 的主观判断,ODown 是多个 Sentinel 的客观判断。
  3. quorum 用于确认客观下线,故障转移还需要选出 Leader Sentinel。
  4. 新 master 优先按 replica priority、复制 offset、runid 选择。
  5. Sentinel 会动态改写配置文件,sentinel.conf 是运行态配置快照。
  6. Sentinel + 主从复制不能保证数据零丢失,网络分区下还要关注 split-brain 风险。

下一篇继续看 Redis Cluster。Cluster 不只是高可用,还解决了单 master 容量有限的问题。


文章作者: hnbian
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hnbian !
评论
  目录