Redis Sentinel

iyuzhang2026-02-24云原生redissentinel

Redis Sentinel High Availability & Observability - Knowledge Base

1. 架构与原理 (Architecture & Concepts)

1.1 拓扑结构 (Topology)

graph TD
    subgraph Monitoring ["Monitoring Layer"]
        G[Grafana :3000] --> P[Prometheus :9090]
        P --> E1[Redis Exporter x6]
    end

    subgraph Sentinel_Cluster ["Sentinel Layer (Quorum=2)"]
        S1[Sentinel 1 :26379]
        S2[Sentinel 2 :26380]
        S3[Sentinel 3 :26381]
    end

    subgraph Data_Layer ["Data Layer (Async Replication)"]
        M[Redis Master :6379]
        R1[Redis Replica 1 :6380]
        R2[Redis Replica 2 :6381]
    end

    E1 -.-> S1 & S2 & S3 & M & R1 & R2
    S1 & S2 & S3 -.->|"Monitor & Failover"| M
    R1 & R2 -->|"Replicate"| M

1.2 核心机制 (Core Mechanisms)

Sentinel Failover Process (故障转移流程)

Redis Sentinel 具备自动 Failover 能力,其核心流程如下:

  1. SDOWN (Subjective Down - 主观下线):
    • 判定: 当一个 Sentinel 节点在 down-after-milliseconds 参数指定的时间内,未收到 Master 的有效回复(如 PING),则该 Sentinel 会将 Master 标记为主观下线。每个 Sentinel 独立进行此判断。
  2. ODOWN (Objective Down - 客观下线):
    • 判定: 当持有 Master SDOWN 状态的 Sentinel 节点数量达到或超过配置的 Quorum 值 (本例为 2) 时,Master 被标记为客观下线。这表明多数 Sentinel 认为 Master 确实出现问题。
    • Quorum vs Majority:
      • Quorum (仲裁): 用于确定 Master 是否客观下线,是 Failover 的触发条件
      • Majority (多数): 用于 Sentinel Leader 选举(SENTINEL is-master-down-by-addr 命令)和 Failover 操作的授权条件。在一个包含 N 个 Sentinel 的集群中,Majority 为 N/2 + 1。本例中 3/2 + 1 = 2
  3. Leader Election (领导者选举):
    • 目的: 一旦 Master 被判定为 ODOWN,Sentinel 集群中的所有 Sentinel 节点会尝试选举出一个 Leader Sentinel 来负责执行后续的 Failover 操作。
    • 过程: 每个 Sentinel 都会向其他 Sentinel 发送请求,希望成为 Leader。第一个收到 Majority 票数的 Sentinel 成为 Leader。
  4. Failover Execution (故障转移执行):
    • 选择 Replica: Leader Sentinel 会从当前 Master 的所有健康 Replicas 中,根据特定规则(优先级 slave-priority -> 复制偏移量 replication offset -> RunID)选择一个最适合的 Replica 升级为新 Master。
    • 角色切换: 向选定的 Replica 发送 REPLICAOF NO ONE 命令,使其成为 Master。
    • 重新配置: 向其他 Replicas 发送 REPLICAOF <new_master_ip> <new_master_port> 命令,使其复制新 Master。
    • Master 更新: 更新所有 Sentinel 对新 Master 的监控配置。

Configuration Epoch (配置纪元)

  • 作用: Configuration Epoch 是一个单调递增的数字,用于标识 Redis Master 及其 Replicas 配置的当前版本。它类似于 Raft 协议中的 Term
  • 机制: 每次 Sentinel 集群成功执行一次 Failover 后,Configuration Epoch 值都会加 1。
  • 冲突解决: Sentinel 使用 Configuration Epoch 来解决配置冲突。如果不同的 Sentinel 持有不同的配置版本,拥有更高 Epoch 的配置(即最新配置)将覆盖旧的配置。这确保了集群中所有 Sentinel 最终会就当前的 Master 状态达成一致。
  • Client 感知: Redis Client 可以订阅 Sentinel 发布的 +switch-master 频道得到主节点地址变更通知;若需 epoch/完整配置,应查看 / 关注 Sentinel 的 sentinel:hello 或通过 SENTINEL 命令查询。

Config Template Pattern (配置模板模式)

容器化环境下,Redis 或 Sentinel 的配置需要兼顾初始化、运行时状态持久化和易于管理。

  • 问题: Sentinel 运行时会重写 sentinel.conf(例如,会添加 known-replica 等状态信息),这部分状态需要持久化。但如果直接挂载宿主机的 sentinel.conf,那么宿主机上的文件就会被修改,不利于版本控制和统一管理。
  • 解决方案:
    1. Read-Only Template (只读模板): 将原始的、版本控制中的配置文件 (如 redis.conf, sentinel.conf) 以 :ro (Read-Only) 模式挂载到容器的特定路径,例如 /etc/redis/xxx.conf.tmpl
    2. Runtime Config (运行时配置): 容器的启动脚本在启动服务前,会检查 /data 目录下是否存在最终要运行的配置文件 (/data/xxx.conf)。
      • 首次启动: 如果 /data/xxx.conf 不存在,则从只读模板 (/etc/redis/xxx.conf.tmpl) 复制一份到 /data/xxx.conf
      • 后续启动: 如果 /data/xxx.conf 已存在,则直接使用该文件,保留 Sentinel 运行时写入的例如 known-replica, current-epoch 等状态信息,容器重启后也不会丢失。

2. 运维操作手册 (Operations Manual)

2.1 状态检查与监控 (Health Check & Monitoring)

Redis Data Node Status (数据节点状态)

使用 redis-cli INFO replication 命令查看 Redis 实例的复制状态:

# 在容器内执行,连接 Master 或 Replica
docker exec -it redis-master redis-cli INFO replication

关键输出指标解读:

  • role:masterrole:slave: 当前实例的角色。
  • connected_slaves:<number>: Master 会显示当前连接的 Replicas 数量。
  • master_host:<ip>, master_port:<port>, master_link_status:up/down: Replica 会显示其 Master 的信息及连接状态。up 表示与 Master 连接正常。
  • master_repl_offset:<offset>, slave_repl_offset:<offset>: 复制偏移量,用于判断主从数据一致性和延迟。两者差值越大,延迟越大。

Redis Sentinel Cluster Status (Sentinel 集群状态)

通过连接任一 Sentinel 节点来获取集群状态:

# 在宿主机执行 (确保 26379 端口已映射)
redis-cli -p 26379 SENTINEL masters

SENTINEL masters 输出解读: 此命令返回 Sentinel 监控的所有 Master 及其详细信息列表。对于每个 Master,会包含:

  • name: Master 的名称 (如 mymaster)。
  • ip, port: Master 的 IP 和端口。
  • runid: Master 的唯一 ID。
  • flags: Master 的状态标志,如 master, s_down, o_down, disconnected 等。
  • link-pending-commands, link-refused-commands: Sentinel 与 Master 连接的健康度。
  • last-ping-sent, last-pong-recv: 最近一次 PING/PONG 时间,用于判断连接活跃度。
  • last-ok-ping-reply: 最近一次 PING 正常回复时间。
  • last-hello-message: 最近一次收到 Sentinel hello 消息的时间。
  • quorum: 配置的 Quorum 值。
  • num-other-sentinels: 除当前 Sentinel 外,还有多少其他 Sentinel 在监控此 Master。
  • num-slaves: 当前 Master 的 Replica 数量。

其他常用 Sentinel 命令:

# 获取 Master 地址
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
# 输出: 1) "172.xx.xx.xx" (IP/Host) 2) "6379" (Port) - 这是客户端连接 Master 的推荐方式

# 查看指定 Master 的 Replicas 详细信息
redis-cli -p 26379 SENTINEL replicas mymaster

# 查看其他 Sentinel 节点的详细信息
redis-cli -p 26379 SENTINEL sentinels mymaster

2.2 故障模拟与恢复 (Failover Simulation)

自动 Failover 演练

  1. 模拟 Master 宕机:
    docker stop redis-master
    
  2. 实时观察 Sentinel 日志: 在另一个终端中监控任一 Sentinel 的日志,观察 Failover 过程。
    docker logs -f sentinel-1
    
    日志关键事件序列:
    • +sdown master ...
    • +odown master ...
    • +vote-for-leader ...
    • +switch-master ... (切换完成)
  3. 验证新 Master: Failover 发生后,通过 Sentinel 查询新的 Master 地址。
    redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
    
  4. 恢复原 Master: 启动原 Master 容器。
    docker start redis-master
    
    • 预期行为: 原 Master 启动后,Sentinel 会检测到它的回归,并自动将其配置为当前新 Master 的 Replica。

手动触发 Failover (Manual Failover)

在某些计划维护场景(如 Master 升级,不需要模拟宕机)下,可以强制 Sentinel 执行一次 Failover:

redis-cli -p 26379 SENTINEL failover mymaster
  • 注意: 即使 Master 仍然健康,此命令也会强制 Sentinel 选出一个 Replica 升级为 Master。

脑裂/无主状态恢复 (Split-brain / No Master State Recovery)

当集群发生网络分区或配置错误,可能导致所有节点都自认为是 Slave (或部分 Sentinel 认为某个旧 Master 仍然存活),形成无主状态或脑裂 (Split-brain)。

  1. 识别最新数据: 通过 INFO replication 检查各个 Replica 的 master_repl_offset,找出数据最全的 Replica。
  2. 强制提升为 Master: 登录到选定的 Replica 容器,将其强制提升为 Master。
    docker exec -it redis-replica-1 redis-cli REPLICAOF NO ONE
    
  3. 指向新 Master: 确保其他 Replica 重新复制新晋 Master。
    # 在 redis-replica-2 容器中
    docker exec -it redis-replica-2 redis-cli REPLICAOF redis-replica-1 6379
    
  4. 重置 Sentinel 状态: 通知所有 Sentinel 重新发现集群拓扑。
    redis-cli -p 26379 SENTINEL reset mymaster
    
    • SENTINEL reset *: 重置所有 Master 的 Sentinel 状态。

3. 故障排查 (Troubleshooting & Pitfalls)

3.1 Host Machine Connection Issues (宿主机连接问题)

DNS Resolution Failure ("Failed to resolve 'redis-master'")

  • 现象: 宿主机上的应用程序成功连接 Sentinel,并通过 Sentinel 发现了 Master 的地址。但当尝试连接该 Master (或 Replicas) 时,抛出 java.net.UnknownHostException: Failed to resolve 'redis-master'
  • 根因分析:
    • Sentinel announce-hostnames yes: 当 Sentinel 配置了 sentinel announce-hostnames yes 时,它会向客户端返回 Docker 内部的 Hostname (如 redis-master, redis-replica-1),而不是容器的 IP 地址。
    • 宿主机 DNS 无法解析: 宿主机运行的应用程序不在 Docker 内部网络,无法解析 Docker 内部的 DNS 名称。宿主机的 DNS 服务器通常不知道 redis-master 这样的内部 Hostname 对应哪个 IP。
  • 解决方案: 修改宿主机的 /etc/hosts 文件,将容器的 Hostname 映射到宿主机的 Loopback 地址。
    # 在 Linux/macOS 上,编辑 /etc/hosts 文件,添加以下行
    # 注意:确保 Master 和所有 Replica 的端口都已正确映射到宿主机
    echo '127.0.0.1 redis-master redis-replica-1 redis-replica-2' | sudo tee -a /etc/hosts
    
    • 原理: 当应用程序尝试连接 redis-master:6379 时,系统会先查询 /etc/hosts,找到 127.0.0.1,然后通过 Docker 映射的 127.0.0.1:6379 端口连接到容器内的 Master。

3.2 Observability Issues (监控问题)

Grafana Permission Denied (权限拒绝)

  • 现象: Grafana 容器启动失败或 Dashboard 无法加载,日志中包含 Permission denied 错误,指向其数据目录 /var/lib/grafana
  • 根因分析: Grafana 容器默认以一个非特权用户 (通常 UID 为 472) 运行。当通过 Docker Volume 将宿主机目录 (如 ./grafana/data) 挂载到容器内部的 /var/lib/grafana 时,如果宿主机目录的权限不正确 (例如,默认属主为 root),则 Grafana 容器内的用户无权写入,导致权限错误。
  • 解决方案: 更改宿主机上挂载目录的所有权和权限。
    # 查找 Grafana 容器的用户 ID (通常是 472)
    # docker image inspect grafana/grafana:11.1.0 --format '{{.Config.User}}'
    
    # 更改挂载目录的所有权为 Grafana 用户 ID,并赋予适当权限
    sudo chown -R 472:472 ./grafana/data ./grafana/provisioning ./grafana/dashboards
    sudo chmod -R 0755 ./grafana/data ./grafana/provisioning ./grafana/dashboards
    

Dashboard "No Data" (Dashboard 无数据)

  • 现象: Grafana Dashboard 导入成功,但显示 "No Data" 或数据面板为空。
  • 根因分析: Grafana Provisioning 机制在导入 Dashboard 时,会根据 Dashboard JSON 文件中的 datasource 配置来关联数据源。如果 JSON 文件中使用了变量 (如 ${DS_PROM}),而 provisioning/datasources/prometheus.yml 中定义的 Datasource UID 与之不匹配,或者变量未被正确解析,就会导致 Dashboard 无法找到对应的数据源,从而显示无数据。
  • 解决方案: 统一 Dashboard JSON 文件和 Provisioning 配置中的 Datasource UID。最简单的方法是将 JSON 文件中 datasource.uid 的值直接修改为 Provisioning 文件中定义的固定 UID,例如 prometheus
    // grafana/dashboards/redis.json 片段
    "datasource": {
        "type": "prometheus",
        "uid": "prometheus" // 将 "${DS_PROM}" 修改为实际的 UID
    },
    
    # grafana/provisioning/datasources/prometheus.yml
    datasources:
      - name: Prometheus
        uid: prometheus # 确保与 JSON 中的 UID 一致
        type: prometheus
        access: proxy
        url: http://prometheus:9090
        isDefault: true
    

3.3 Podman Compatibility (Podman 兼容性)

  • 现象: 在 Podman 环境中运行此 Docker Compose 栈时,Sentinel 启动报错 Failed to resolve hostname,或 Sentinel 无法正常 Monitor Master。
  • 根因分析: Podman 的网络栈与 Docker Engine 存在差异。虽然两者都支持容器间 Hostname 解析,但在某些 Podman 版本或非 Root 模式下,其内置 DNS 解析机制可能不如 Docker 稳定。
  • 建议: 鉴于此 Lab 环境是为 Docker Compose 设计,建议优先在标准 Docker 环境下运行。如果必须使用 Podman,请查阅 Podman 官方文档关于容器网络和 DNS 解析的最新说明,并可能需要安装额外的网络插件。

4. 常用命令速查 (Cheat Sheet)

4.1 Redis Data Node Commands (数据节点命令)

这些命令用于检查 Redis 实例的运行状况、性能和数据。

命令作用示例或解释
INFO memory查看内存使用详情详细显示 used_memory_human (已用内存)、mem_fragmentation_ratio (内存碎片率) 等,有助于内存优化。
INFO clients查看连接客户端统计显示 connected_clients (连接数)、client_longest_output_list (最大输出列表长度) 等,用于排查连接数异常。
CLIENT LIST列出所有连接的客户端详情逐行显示每个 Client 的 id, addr, fd, name, age, idle, flags, cmd 等信息,有助于排查慢查询或连接泄露。
MONITOR警告:慎用! 实时打印所有接收到的命令用于高度调试目的,但在生产环境高负载下会严重影响性能,且输出量巨大。
SLOWLOG GET <count>获取最近的慢查询日志获取 slowlog-log-slower-than 参数配置阈值以上的慢查询。SLOWLOG GET 10 查看最近 10 条。
CONFIG GET *获取运行时配置参数查看所有或指定配置项的当前值,如 CONFIG GET maxmemory
redis-cli --bigkeys扫描占用大量空间的 Key分析数据库中 String、List、Set、Hash、ZSet 五种数据类型中 Key 的分布和大小,有助于发现潜在的性能瓶颈。
redis-cli --memkeys扫描占用内存最多的 Key类似 --bigkeys,但更侧重于按实际内存占用排序,需要 Redis 4.0+。

4.2 Redis Sentinel Node Commands (Sentinel 节点命令)

这些命令用于管理和查询 Sentinel 集群的状态和行为。

命令作用示例或解释
SENTINEL masters列出 Sentinel 监控的所有 Master包含 Master 的 name, ip, port, runid, flags, num-slaves, num-other-sentinels 等详细信息。
SENTINEL slaves mymaster列出指定 Master 的所有 Replicas包含每个 Replica 的 ip, port, runid, flags (如 s_down), master-link-status, last-ping-sent 等。
SENTINEL sentinels mymaster列出监控指定 Master 的其他 Sentinel 节点返回其他 Sentinel 的 ip, port, runid 等信息。
SENTINEL ckquorum mymaster检查当前 Sentinel 是否满足 Failover 的 Quorum 条件告知是否能够立即进行 Failover。
SENTINEL failover mymaster强制 Sentinel 启动一次针对 mymaster 的 Failover即使 Master 运行正常也会强制切换,常用于计划性维护。
SENTINEL reset mymaster重置指定 Master 的 Sentinel 状态清除该 Sentinel 对 mymaster 的所有已知状态信息(如 Replicas, 其他 Sentinels),并尝试重新发现。SENTINEL reset * 重置所有 Master。在修复配置错误或从脑裂中恢复时很有用。
SENTINEL flushconfig强制 Sentinel 将内存中的配置写入 sentinel.conf通常在动态修改 Sentinel 配置后(如通过 SENTINEL set 命令)用于持久化变更。
SENTINEL monitor <name> <ip> <port> <quorum>动态添加监控一个 Master在 Sentinel 运行时添加新的监控 Master。
SENTINEL remove <name>动态停止监控一个 Master在 Sentinel 运行时移除对某个 Master 的监控。

5. 参考资料 (References)

最后更新时间 2/26/2026, 9:56:06 AM