Redis 高可用:Sentinel 选举、Cluster 迁移与一致性边界
自动切主不等于写入永不丢失。Sentinel 管理非分片主从的故障转移,Cluster 同时管理分片与故障转移;两者都依赖异步复制。本文以 Redis Open Source 7.2 的经典机制为基线,迁移部分描述显式 MIGRATING/IMPORTING 流程。以下时序和命令均为说明,未连接 Redis 实测。
Sentinel:判定下线与授权切换是两件事
单个 Sentinel 在 down-after-milliseconds 内持续得不到有效响应,会标记主观下线 SDOWN。对于主库,收集到配置的 quorum 个 Sentinel 同意后,才形成客观下线 ODOWN。但 quorum 解决“是否认为主库故障”,不是“谁有权切换”。
候选 Sentinel 在一个选举 epoch 内请求投票,每个 Sentinel 在该轮最多投给一个候选者。执行切换需要同时满足多数 Sentinel 授权和配置的 quorum 门槛。例如总数五个、quorum 为二,两个能互通只能判定下线,至少三个授权才能切换;quorum 为四时,三个也不够。因此调低 quorum 不能让少数分区合法接管。这里选的是主持切换的 Sentinel,不是直接把某个 Redis 从库选成领导者。
获授权后,主持者从合格从库中选择晋升对象:先排除断连过久等不合格者,再比较 replica-priority(较小优先,零表示不参与)、复制 offset(较大优先),最后按 run ID 打破平局。只看 offset 会忽略运维设置的晋升优先级。
选举 epoch 标识投票轮次,配置 epoch 为切换后的主库配置提供版本。Sentinel 传播配置时接受更新的版本,使地址视图收敛;它不是每条写入的提交序号,也不能证明新主库包含旧主库全部数据。Sentinel 需要可写配置文件保存状态。细节见官方 Sentinel 文档。
Cluster:槽归属与数据副本分开理解
Cluster 将键空间分为 16384 个槽,一般按 CRC16(key) mod 16384 定位。order:{42}:meta 与 order:{42}:items 使用花括号内相同的非空 hash tag,可落在同一槽;不是只要位于同一节点就能执行多键操作。跨槽多键请求会遭遇 CROSSSLOT,滥用固定 tag 又会把负载集中到一个槽。
Cluster 不依赖 Sentinel 切主。通常由服务槽的主节点多数授权从库晋升;currentEpoch 表示逻辑轮次,主节点的 configEpoch 为槽配置提供版本。同一槽出现归属冲突时,更高配置 epoch 的声明胜出。它解决路由配置冲突,不合并两份业务数据。算法依据见官方 Cluster 规范。
迁移中为什么同时需要 ASK 与 MOVED
将槽 s 从 A 迁到 B 时,先让 B 标记 IMPORTING、A 标记 MIGRATING,再逐批搬键,最后更新槽归属。此时同一个槽的键可能分布在两端,不能在第一次重定向后就认为整个槽都搬完了。
| 响应 | 客户端动作 | 路由缓存 |
|---|---|---|
| ASK | 在目标连接先发 ASKING,再重发该请求 | 本次临时跳转,不改槽归属 |
| MOVED | 向返回地址重发,并更新槽映射或刷新拓扑 | 后续按新归属路由 |
| TRYAGAIN | 多键在迁移期间无法一起处理时,有限退避重试 | 不代表新的归属 |
A 对仍存在的键继续服务,对已不在本地的键返回 ASK。B 处于 IMPORTING 时,需要同一连接上的 ASKING 才接纳这次请求;它只影响下一条命令。迁移完成后用 MOVED 告知正式归属。状态含义见官方 CLUSTER SETSLOT。客户端应设置重定向与重试上限;连接超时意味着执行结果可能未知,不能无条件重放扣款或计数。
为什么仍不能承诺强一致
考虑:主库执行写入并回复 OK → 从库尚未收到 → 主库失联 → 从库晋升。新主库没有这笔已确认写入,旧主库恢复后跟随新历史,也不会自动合并分叉。这条时序同时适用于 Sentinel 与 Cluster 的异步复制窗口。
WAIT 可等待同一连接之前的写入被指定数量副本确认,但不会把 Redis 变成强一致系统。min-replicas-to-write 根据健康副本情况限制写入,也不是每笔写入的多数提交协议。AOF 落盘则解决另一类故障。需严格保障的账务状态,应由具备所需事务与一致性保证的权威存储承担,并用幂等标识、对账处理缓存与重试的不确定性。
故障定位清单:先取证再改变拓扑
下面是只读诊断入口示意,地址按实际隔离环境替换;不是本次执行记录。
redis-cli -h sentinel-host -p 26379 SENTINEL CKQUORUM mymaster
redis-cli -h sentinel-host -p 26379 SENTINEL MASTER mymaster
redis-cli -h data-host -p 6379 INFO replication
redis-cli -h cluster-host -p 7000 CLUSTER INFO
redis-cli -h cluster-host -p 7000 CLUSTER NODES- 不切主:核对 SDOWN/ODOWN、
+elected-leader、+switch-master日志与时间线;检查可达 Sentinel 数、quorum、ACL、配置可写性,以及是否存在合格从库。CKQUORUM 通过只说明当前票数条件可满足,不保证切换成功。 - 已切主仍写旧节点:比较 Sentinel 返回地址、数据节点角色和连接池实际端点;排查客户端发现机制、旧连接、NAT 公布地址。Sentinel 不代理数据请求。
- 重定向循环或超时:对比各节点槽视图、迁移标记和 configEpoch,检查返回地址从应用侧是否可达;同时检查 cluster bus 网络。单个种子节点可连,不等于整个集群可访问。
- CLUSTERDOWN 或丢写:查看槽覆盖、失败节点、多数主节点可达性及
cluster-require-full-coverage;关联复制 offset、主从断连和切换时刻。不要把重启或强制接管当作取证第一步。
预期失败样例(未执行):在隔离 Cluster 中对 a{1}、b{2} 执行 MGET,应得到 CROSSSLOT;普通客户端访问错误槽节点可能收到 MOVED,说明应启用 Cluster 路由支持,而非服务器自动转发。
