Redis Sentinel
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 能力,其核心流程如下:
- SDOWN (Subjective Down - 主观下线):
- 判定: 当一个 Sentinel 节点在
down-after-milliseconds参数指定的时间内,未收到 Master 的有效回复(如 PING),则该 Sentinel 会将 Master 标记为主观下线。每个 Sentinel 独立进行此判断。
- 判定: 当一个 Sentinel 节点在
- 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。
- Leader Election (领导者选举):
- 目的: 一旦 Master 被判定为 ODOWN,Sentinel 集群中的所有 Sentinel 节点会尝试选举出一个 Leader Sentinel 来负责执行后续的 Failover 操作。
- 过程: 每个 Sentinel 都会向其他 Sentinel 发送请求,希望成为 Leader。第一个收到 Majority 票数的 Sentinel 成为 Leader。
- 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 的监控配置。
- 选择 Replica: Leader Sentinel 会从当前 Master 的所有健康 Replicas 中,根据特定规则(优先级
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,那么宿主机上的文件就会被修改,不利于版本控制和统一管理。 - 解决方案:
- Read-Only Template (只读模板): 将原始的、版本控制中的配置文件 (如
redis.conf,sentinel.conf) 以:ro(Read-Only) 模式挂载到容器的特定路径,例如/etc/redis/xxx.conf.tmpl。 - 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等状态信息,容器重启后也不会丢失。
- 首次启动: 如果
- Read-Only Template (只读模板): 将原始的、版本控制中的配置文件 (如
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:master或role: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 演练
- 模拟 Master 宕机:
docker stop redis-master - 实时观察 Sentinel 日志: 在另一个终端中监控任一 Sentinel 的日志,观察 Failover 过程。日志关键事件序列:
docker logs -f sentinel-1+sdown master ...+odown master ...+vote-for-leader ...+switch-master ...(切换完成)
- 验证新 Master: Failover 发生后,通过 Sentinel 查询新的 Master 地址。
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster - 恢复原 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)。
- 识别最新数据: 通过
INFO replication检查各个 Replica 的master_repl_offset,找出数据最全的 Replica。 - 强制提升为 Master: 登录到选定的 Replica 容器,将其强制提升为 Master。
docker exec -it redis-replica-1 redis-cli REPLICAOF NO ONE - 指向新 Master: 确保其他 Replica 重新复制新晋 Master。
# 在 redis-replica-2 容器中 docker exec -it redis-replica-2 redis-cli REPLICAOF redis-replica-1 6379 - 重置 Sentinel 状态: 通知所有 Sentinel 重新发现集群拓扑。
redis-cli -p 26379 SENTINEL reset mymasterSENTINEL 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。
- Sentinel
- 解决方案: 修改宿主机的
/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 的监控。 |
