Redis 集群的实现原理是什么?
- 标签:后端、Redis
🏛 业务架构师
Redis 集群(Cluster)的核心机制三条:哈希槽分片(16384 个 slot 按 CRC16(key) mod 16384 落位)、节点间 Gossip 协议交换拓扑、主从+自动故障转移。客户端可直连任意节点,不归它管的 key 返回 MOVED 重定向(智能客户端本地缓存槽位映射,smart client)。
业务上我更想讲什么阶段才该上集群,这是投入产出判断:
先确认瓶颈真实存在:
- 单机内存到 25GB 以上、fork 生成 RDB 的停顿开始影响请求;
- 写入 QPS 接近单机上限(约 10 万级);
- 需要横向扩容能力。
集群的代价(很多人低估):
- 多 key 操作受限:mget、事务、Lua 涉及的 key 必须同槽,要么按 hash tag
{user1}:orders人为聚簇(又制造热点风险),要么放弃批量操作; - 运维复杂度翻倍:槽迁移、扩缩容、故障演练都是专业活,小团队常被反噬;
- 客户端行为变化:重定向、拓扑刷新。
我的演进路线:单机(绝大多数业务到此为止)→ 主从+哨兵(要高可用)→ 先做业务垂直拆分(把不同业务的 Redis 实例分开,多数"内存不够"其实是业务混部)→ 最后才集群。见过太多日活十万的系统强行上集群,然后被 hash tag 和跨槽问题折磨——容量问题优先用"拆实例"解决,分片是最后手段。
🏗 系统架构师
Redis 集群(Redis Cluster)我按"数据分布 + 路由 + 高可用 + 扩缩容"讲:
- 数据分片:16384 个哈希槽,
slot = CRC16(key) mod 16384,槽分配到各主节点。key 按 hash tag({user1}.xxx)可强制同槽,做多 key 操作; - 智能客户端路由:客户端可直连任意节点,节点不是自己负责的槽返回 MOVED(客户端缓存槽位映射);迁移期间返回 ASK 让客户端临时去新节点查;
- 高可用:每个主节点挂 1~N 个副本,主挂后其余主节点间 Gossip 投票选主(超过半数认定下线即 failover),无需哨兵组件;
- 扩缩容:槽迁移是逐 key 的
MIGRATE,同步阻塞毫秒级,可在线操作但大 key 迁移要小心。
权衡与限制:
- 无中心架构换来了水平扩展(官方建议 ≤1000 主节点),代价是多 key 事务/Lua 限制在同槽、客户端复杂、不支持多库;
- 半数以上主节点不可用则集群整体不可用——机房级故障要靠多机房部署;
- 容量规划我按单节点内存 ≤ 10~25GB 设计,太大反而拖慢 fork/RDB 与故障恢复。
💻 全栈开发专家
Redis Cluster 的核心是 16384 个哈希槽(slot):
- 分片:
slot = CRC16(key) % 16384,每个 master 负责一段槽位区间。节点数 × 槽区间就能水平扩容。 - 路由:客户端可连任意节点,key 不归它管就回
MOVED(槽已迁移完成)或ASK(迁移中),smart client(如 Lettuce/Redisson)本地缓存槽位表直连目标节点,基本一次网络往返。 - ** gossip 协议**:节点间 PING/PONG 交换集群拓扑、故障检测,无中心元数据节点。
- 高可用:每个 master 挂 1~N 个 replica,master 失效经多数派检测后自动提升从库。
我踩过的生产坑:
- 多 key 操作要求同 slot:
MGET key1 key2跨槽直接报错。解法是 hash tag:user:{1001}:profile,花括号内相同就落同一槽。 - 扩容迁移期间:运维用
redis-cli --cluster reshard槽迁移要避开高峰,大 key 迁移会卡。 - 客户端要开启拓扑刷新(Lettuce
enableAllAdaptiveRefreshTriggers),否则故障切换后一直打旧节点。
集群解决容量和写扩展;哨兵解决高可用不扩容,选型先看数据量。