Skip to content

哨兵模式

Redis Sentinel 是主从架构外面的一层"观察者和调度者"——一组 Sentinel 进程持续监控主库和从库,发现主库不可用后投票确认故障,再从从库中选一个提升为新主库,通知其他从库改挂新主。

Sentinel 解决的是主从的自动切换问题,不解决分片扩容问题。数据容量和写入压力仍然由单个主库承担。需要多主分片时看 Redis Cluster。

一、Sentinel 的部署结构

Sentinel 进程和 Redis 进程是分开的——它监听独立的端口(默认 26379),使用独立的配置文件和 systemd unit。Sentinel 可以和 Redis 部署在同一台机器上,也可以分开部署。

至少需要 3 个 Sentinel 节点。原因不是"3 个比较好看",而是 Sentinel 需要投票达成共识(quorum)才能确认故障——1 个节点自身故障就被误判,2 个节点出现网络分区时无法区分"对方挂了"和"网络断了"。3 个节点用奇数,投票不出现平局。

示例拓扑:

角色地址Redis 端口Sentinel 端口
Redis master192.168.10.11637926379
Redis replica192.168.10.129637926379
Redis replica192.168.10.130637926379

先配好 Redis 主从,再部署 Sentinel。Sentinel 的配置对象是"已经存在的主从拓扑"。

二、Sentinel 配置文件

sentinel.conf

conf
port 26379
daemonize no
supervised systemd
dir /data/redis-sentinel
logfile /var/log/redis/sentinel.log

sentinel monitor mymaster 192.168.10.11 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

关键配置的含义:

  • sentinel monitor mymaster 192.168.10.11 6379 2:告诉 Sentinel 监控主库 192.168.10.11:6379,命名为 mymaster(这个名字会被客户端用来查询主库地址),最后的 2 是 quorum——至少 2 个 Sentinel 同意才算客观下线。
  • down-after-milliseconds 5000:单个 Sentinel 在 5 秒内没有收到主库的正常响应,就把它标记为 SDOWN(主观下线)。
  • failover-timeout 60000:故障转移各阶段的总超时时间。如果 60 秒内切换没完成,就放弃本次尝试。
  • parallel-syncs 1:切换完成后,允许多少个从库同时并行同步新主。设为 1 表示一次只同步一个,避免新主同时给所有从库发 RDB 压力太大。

如果 Redis 有密码:

conf
sentinel auth-pass mymaster strong_password_here

Sentinel 在运行过程中会自动重写 sentinel.conf,把发现的从库、其他 Sentinel 节点、当前主库状态写进去。所以 sentinel.conf 文件需要对 Redis 运行用户有写权限,且不要设置为只读。自动重写的内容是 Sentinel 的"运行时记忆"——重启后靠这些记录恢复对拓扑的认知。

三、systemd 管理 Sentinel

ini
# /etc/systemd/system/redis-sentinel.service
[Unit]
Description=Redis Sentinel
After=network.target

[Service]
Type=notify
User=redis
Group=redis
ExecStart=/usr/local/redis/bin/redis-sentinel /etc/redis/sentinel.conf --supervised systemd
Restart=on-failure
RestartSec=5
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target

启动:

bash
systemctl daemon-reload
systemctl enable --now redis-sentinel

四、查看 Sentinel 状态

Sentinel 用 redis-cli 连接到它的端口(26379),用 SENTINEL 系列子命令管理:

bash
redis-cli -p 26379 PING

# 查看当前监控的主库
redis-cli -p 26379 SENTINEL master mymaster

# 查看从库列表
redis-cli -p 26379 SENTINEL replicas mymaster

# 查看其他 Sentinel 节点
redis-cli -p 26379 SENTINEL sentinels mymaster

# 获取当前主库的地址(客户端最常用的查询)
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster

SENTINEL get-master-addr-by-name 是客户端发现主库的核心命令。应用不写死主库 IP,而是通过 Sentinel 查询当前主库地址——切换后查询结果自动指向新主库。但前提是客户端的连接库(如 Jedis、Lettuce、redigo)支持 Sentinel 模式并正确配置了 Sentinel 地址列表。

五、主观下线(SDOWN)和客观下线(ODOWN)

Sentinel 判断故障分两层:

状态触发条件含义
SDOWN(主观下线)单个 Sentinel 在 down-after-milliseconds 时间内没收到主库正常响应"我认为它挂了"
ODOWN(客观下线)达到 quorum 数量的 Sentinel 都报告 SDOWN"大家投票确认它挂了"

只有进入 ODOWN 后,Sentinel 才会启动故障转移。这两个阶段的设计是为了防止单个 Sentinel 因为自身网络问题而误判主库故障。

quorum 值的选择:

  • 3 个 Sentinel,quorum = 2:任意 1 个出问题(宕机或网络分区),还有 2 个可以正常投票
  • 5 个 Sentinel,quorum = 3:容忍 2 个出问题

quorum 太低容易误判——比如网络抖动导致 2 个 Sentinel 暂时连不上主库;quorum 太高可能真的故障时凑不够票,切换迟迟不触发。

六、故障转移的过程中做了什么

主库被确认为 ODOWN 后:

text
1. Sentinel 之间选举一个 leader(由这个 leader 主导本次故障转移)
2. Leader 从可用从库中选一个作为新主库
3. Leader 向新主库发送 REPLICAOF NO ONE,将其提升为主库
4. Leader 通知其他从库改为复制新主库
5. Leader 更新自己的配置
6. 客户端通过 SENTINEL get-master-addr-by-name 查询到新地址

选主(第二步)时的权衡因素:

因素优先
从库是否在线下线的直接排除
复制偏移量offset 越大越好,数据越新
replica-priority值越小优先级越高,0 表示永不提升
运行 ID以上都相同时按运行 ID 排序

如果有一台从库只用于备份、不希望被提升为主库:

conf
replica-priority 0    # 这个从库永远不会被 Sentinel 提升为主库

七、手动触发切换

维护窗口里(比如要重启主库所在机器),可以先手动触发一次平滑切换:

bash
redis-cli -p 26379 SENTINEL failover mymaster

这会让 Sentinel 主动执行一次故障转移——原主库变成从库,选一个从库提升。和被动故障切换的区别是:旧主库在线的情况下可以平滑交接,不会有数据丢失。

手动切换后验证:

bash
# 确认新主库地址
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster

# 在新主库上做写入测试
redis-cli -h <新主库IP> -p 6379 SET test:failover "$(date +%s)"
redis-cli -h <新主库IP> -p 6379 GET test:failover

八、客户端如何适配 Sentinel

客户端不能写死主库 IP——写死的话 Sentinel 切换了,应用还连着旧地址。正确的接入方式:

text
客户端配置:
  - Sentinel 地址列表:192.168.10.11:26379, 192.168.10.129:26379, 192.168.10.130:26379
  - master 名称:mymaster

客户端内部流程:
  Sentinel 列表 → 任意一个 Sentinel 响应 → 查询 mymaster 的主库地址 → 连接该地址
  → 订阅 Sentinel 的切换事件 → 主库地址变更时重连新主库

客户端要能处理"查到的地址突然连不上"的情况——更新主库地址后立即重连新主库,而不是一直重试旧地址。

九、切换后常见的"看起来切换了但业务没好"

Sentinel 报告切换成功,不等于业务恢复了。几个经常出问题的环节:

问题原因怎么确认
应用还连着旧主库客户端直接写死了 IP检查客户端配置是否使用 Sentinel
连接池没刷新连接池里的旧连接还保留着检查连接池是否在收到切换事件后重建连接
旧主库恢复后又写入旧主库重启后没有加 replicaof,以独立主库身份运行检查旧主库的 INFO replication 角色
新主库不可写replica-read-only 没取消,或 REPLICAOF NO ONE 没成功在新主库上执行写入测试

旧主库恢复后的处理是容易出问题的环节——如果直接启动但没有配置 replicaof,它就成为一个独立主库。此时系统中存在两个"主库",各自接受写入,数据出现分叉。恢复旧主库的正确方式是让它以从库身份加入,挂到新主库下面。

十、通知脚本

Sentinel 可以在发生关键事件时执行外部脚本:

conf
sentinel notification-script mymaster /usr/local/bin/redis-sentinel-notify.sh

脚本示例:

bash
#!/bin/bash
set -euo pipefail
event="$1"
master="$2"
logger -t redis-sentinel "event=$event master=$master args=$*"

脚本里不适合写太重的逻辑——调外部 API 失败或执行时间过长会影响 Sentinel 自身工作。更稳妥的做法是脚本只记录和投递事件(发一条消息到监控系统),复杂处理交给外部系统。

十一、常见故障排查

主库故障但没有切换

bash
# 看有多少 Sentinel 在线
redis-cli -p 26379 SENTINEL sentinels mymaster

# 看主库在 Sentinel 眼中的状态
redis-cli -p 26379 SENTINEL master mymaster

常见原因:Sentinel 节点之间不通(无法形成 ODOWN)、quorum 设置太高凑不够票、所有从库的 replica-priority 都是 0、或者 Sentinel 和主库之间的网络没断但主库和客户端之间断了(Sentinel 角度看主库还活着)。

Sentinel 看不到从库:从库的 replicaof 配置是否正确、从库和 Sentinel 之间的网络可达性、sentinel auth-pass 密码是否正确。

切换后应用报错:十有八九是客户端没接 Sentinel,或者连接池没刷新。

Sentinel 是主从架构上的自动切换组件,不是完整高可用方案的全部。应用连接、网络隔离、监控告警、旧主库恢复流程,这些缺一个都会让自动切换的效果大打折扣。