面试考察点

  • 是否理解 16384 个哈希槽与节点映射。
  • 能否区分 MOVED 和 ASK 重定向。
  • 是否知道高可用不能消除异步复制的数据风险。

核心答案

Redis Cluster 把键映射到 16384 个槽,再把槽分配给主节点。客户端根据槽路由请求,拓扑变化时通过 MOVED 更新长期映射;槽迁移过程中可能通过 ASK 临时访问目标节点。每个主节点可配置从节点参与故障转移。

集群使用异步复制,主节点故障时仍可能丢失尚未复制的数据,因此它提供高可用而不是强一致。

槽与多键操作

Key 的槽由 CRC16 计算;{} hash tag 可让相关 Key 落在同一槽,从而支持特定多键命令或 Lua 脚本。但过度使用同一 tag 会造成数据和流量倾斜。

槽路由的实际过程

客户端对 key 计算槽号,查询本地缓存的“槽 -> 主节点”拓扑,直接向对应节点发送命令。若拓扑已变化:

  • MOVED slot host:port 表示该槽已稳定归属新节点,客户端应更新槽映射并重试。
  • ASK slot host:port 常出现在迁移窗口,客户端临时向目标节点发送 ASKING 后重试,但不应永久更新映射。

使用 Cluster 时需要支持重定向和拓扑刷新。把普通单机 Redis 客户端直接连到一个 Cluster 节点,可能在跨槽访问时反复失败或性能异常。

主从与故障转移边界

每个槽由一个主节点提供写服务,从节点异步复制。集群节点通过 gossip 交换健康和槽信息,检测到主节点故障后,由从节点发起选举成为新主。复制是异步的:客户端刚收到写成功,主节点尚未来得及把日志复制给从节点就故障,该写入仍可能丢失。

要根据 RPO/RTO 决定副本数、故障域、写确认策略和是否允许在副本不足时继续写。Redis Cluster 提高可用性,不等同于关系数据库的强一致复制。

多 Key 与 hash tag 设计

cart:{user:1001}:items
cart:{user:1001}:meta

花括号内相同部分决定槽,两个 key 可以在同一节点执行 Lua 脚本或事务。不要把所有 key 都写成 {global},那会让整个集群退化为一个热点槽。hash tag 应只用于确实需要原子处理的一小组相关数据。

跨槽的 MGET、事务和 Lua 通常受限制。应用需要拆成多个请求再在上层合并,或重新建模,让必须原子处理的数据天然共享同一槽。

扩缩容与迁移预案

迁移一个槽需要把该槽 key 逐步从源主节点搬到目标主节点,期间会产生 ASK 重定向。大 Key、热点 Key、网络带宽和 AOF/RDB 压力会影响迁移时间。生产操作前应:

  1. 检查每节点槽数、内存、CPU、复制延迟和大 Key。
  2. 小批量迁移并观察命令延迟、重定向率和客户端错误。
  3. 确认新节点副本和故障域分布,留出故障时的接管容量。
  4. 完成后验证槽覆盖、读写一致性和客户端拓扑刷新。

缩容比扩容更危险,因为目标节点要承接全部数据与流量;不能只看平均内存,还要看热点和故障冗余。

常见线上故障

集群状态为 fail 可能是槽未完全覆盖、多个主节点不可达或网络分区;频繁 MOVED 可能是客户端没有刷新拓扑;某个节点 CPU 高而其他节点空闲往往是 Key 分布或热点问题,而非简单“集群失效”。诊断应从槽、Key 和命令维度下钻。

扩缩容

扩容的本质是把一部分槽及其 Key 从旧节点迁移到新节点,期间客户端必须正确处理重定向。操作前评估大 Key、热点、网络和持久化压力,并分批执行和校验。

常见误区

Cluster 不代理所有请求,智能客户端需要维护拓扑。多数派故障检测与故障转移提高可用性,但网络分区、复制延迟和同时故障仍需纳入 RPO/RTO 设计。

高频追问与参考回答

追问:为什么槽数不是节点数?

槽作为稳定的逻辑分片层,把数据映射与物理节点解耦,扩缩容只需迁移部分槽,不必为每个 Key 重新定义节点规则。

追问:Cluster 能保证读到主库最新数据吗?

从副本读取时可能受到复制延迟影响;读取主节点通常更接近最新已处理写,但网络、故障和客户端重试语义仍要按业务要求设计。

追问:为什么集群节点数增加后单个热 Key 还是慢?

一个 Key 不会拆到多个槽,所有命令仍由一个主节点串行处理。需要本地缓存、请求合并、读副本、Key 副本或业务分片解决。

追问:迁移时业务需要停机吗?

正常槽迁移可在线进行,客户端正确处理 ASK/MOVED 即可;但大规模迁移和资源紧张时仍可能影响延迟,应限速、灰度并准备回退。

总结

Cluster 用槽实现水平分片,用副本和选举实现故障转移;客户端路由、迁移和一致性边界同样是设计重点。

机制全景图

下面把「Redis Cluster 的分片和故障转移原理是什么?」从输入到结果压缩成一条可复述的主链路。面试时先用图建立全局坐标,再进入局部实现,能避免只背零散结论。

flowchart LR
    A["对 Key 计算 CRC16"]
    A --> B["映射到 16384 槽"]
    B --> C["客户端路由到节点"]
    C --> D["MOVED/ASK 重定向"]
    D --> E["迁移槽并恢复副本"]

完整链路:从输入到结果

沿着「对 Key 计算 CRC16 → 映射到 16384 槽 → 客户端路由到节点 → MOVED/ASK 重定向 → 迁移槽并恢复副本」观察输入、状态与输出,下面每个阶段都对应一个可以在源码、日志或系统表中验证的位置。

1. 对 Key 计算 CRC16

Cluster 以 hash slot 而非节点数直接映射,槽作为扩容迁移的最小路由单位。

2. 映射到 16384 槽

普通 Key 通过 CRC16%16384 定位;hash tag 可让多个 Key 落同槽以支持多键命令。

3. 客户端路由到节点

客户端缓存槽位拓扑并直连目标主节点,拓扑变化时更新映射。

4. MOVED/ASK 重定向

MOVED 表示稳定归属改变,ASK 表示迁移中的临时访问,客户端处理方式不同。

5. 迁移槽并恢复副本

reshard 在节点间迁移槽内 Key,故障转移由副本晋升,但少数写入仍受异步复制窗口影响。

源码与实现定位

入口 阅读重点
src/cluster.c keyHashSlot CRC16 与 hash tag
CLUSTER SLOTS/SHARDS 槽位、节点与迁移状态

源码或系统表应按上表顺序追踪:先确认入口实际走到哪条路径,再用运行时数据验证,而不是仅凭类名或配置推测。

参数配置与可复现实验

redis-cli --cluster check host:6379
redis-cli CLUSTER SHARDS

统计每槽 Key/QPS,迁移含 Big Key 的槽并注入 MOVED/ASK,验证客户端拓扑刷新和延迟。

验证步骤与预期结果

1. 固定输入和基线

先在没有故障注入的环境执行上述配置,固定数据规模、并发度、运行时版本和预热时间。以「最大/平均槽QPS」为主基线,记录值应满足「<2」;同时保存 各槽 Key/QPS 分布、cluster_state,使后续变化能够回到同一时间轴比较。

2. 从实现入口确认路径

在「src/cluster.c keyHashSlot」确认请求确实进入「CRC16 与 hash tag」对应的实现,再沿「CLUSTER SLOTS/SHARDS」观察「槽位、节点与迁移状态」。如果入口路径都未命中,就不应继续调整下游参数,而应先检查调用条件、版本或路由是否与假设一致。

3. 注入本文特有的失败模式

优先复现「全局 hash tag 制造单槽热点」,并把单一变量逐级放大,直到「最大/平均槽QPS」越过「>3」。随后再分别验证「客户端不处理 ASK/MOVED」和「槽迁移时执行大 Key 阻塞」,三类故障分开执行,避免多个变量同时变化而无法归因。

4. 执行止损和根因修复

第一轮只应用「移除全局 hash tag」,确认它能控制影响范围;第二轮应用「客户端正确处理 MOVED/ASK」,验证核心链路恢复;最后落实「迁移前治理 Big Key」,消除同类问题再次出现的条件。每一步都保留变更前后数据,不用“感觉变快了”替代测量。

5. 通过退出条件

实验只有同时满足三项才算通过:「最大/平均槽QPS」回到「<2」、「重定向率」回到「稳态接近0」、「迁移 P99」回到「预算内」,并且业务结果差异为零。若性能恢复但结果不一致,仍应视为失败;若指标恢复后很快再次越线,则说明只完成了临时止损,没有消除根因。

量化基线

指标 样例基线/口径 风险线 结论
最大/平均槽QPS <2 >3 槽热点
重定向率 稳态接近0 持续增长 拓扑缓存旧
迁移 P99 预算内 Big Key 长尾 先拆 Key

这些数值是实验口径或示例告警线,不是可复制到所有系统的固定答案;上线阈值应由本系统稳态、峰值和故障演练共同确定。

事故复盘:使用 hash tag 后单节点过热

为支持批量 Lua,团队把所有租户 Key 都写成 {global}:xxx,结果全部落同一槽,集群形同单节点。hash tag 应只绑定确需原子操作的小范围业务实体,而不是全局命名空间。

失败模式 首要证据 第一处置动作
全局 hash tag 制造单槽热点 各槽 Key/QPS 分布 移除全局 hash tag
客户端不处理 ASK/MOVED cluster_state 客户端正确处理 MOVED/ASK
槽迁移时执行大 Key 阻塞 重定向次数 迁移前治理 Big Key

发布与回滚检查点

  • 发布前:确认「src/cluster.c keyHashSlot」对应实现和上述配置在目标版本仍然有效,并保存「最大/平均槽QPS」基线。
  • 灰度中:同时观察 各槽 Key/QPS 分布、cluster_state、重定向次数;任一指标越过表中风险线,就停止继续扩量。
  • 回滚时:先执行「移除全局 hash tag」控制影响,再回退代码或参数;涉及持久状态时必须额外核对结果差异。
  • 发布后:至少覆盖一个完整峰值周期,确认「全局 hash tag 制造单槽热点」没有再次出现,才关闭变更观察窗口。

方案对比与选型

方案 更适合的场景 主要收益 代价与边界
Cluster 数据量和吞吐需水平扩展 原生分片与故障转移 跨槽多键限制、客户端更复杂
客户端一致性哈希 可控分片中间层 规则灵活 迁移和高可用需自行实现
单实例主从 容量足够且操作依赖多键 语义简单 垂直容量上限明显

选型至少带上 Key 数量、Value 大小、命令复杂度、热点分布和过期速率,并用上面的量化基线验证;未知数据应明确为待测假设。

设计边界与工程取舍

Cluster 扩展的是多 Key 总吞吐,无法拆分一个热 Key;跨槽原子性和强一致也不会因增加节点自动获得。

工程落地遵循:Redis 是高性能数据结构服务,不应被当成没有容量边界的黑盒。回答时直接引用「src/cluster.c keyHashSlot」、配置实验和事故数据,比复述固定模板更有说服力。