Redis Cluster 集群
1. Redis Cluster 是什么?
Redis Cluster 是 Redis 官方提供的分布式集群方案,核心目标是同时解决两个问题:
- 数据分片:把数据分散到多个 master 节点上,突破单机内存和单机写入瓶颈。
- 高可用:每个 master 可以配置 replica,master 故障后 replica 可以自动晋升为新 master。
典型结构如下:
Redis Cluster
Master1 Master2 Master3
slots 0-5460 slots 5461-10922 slots 10923-16383
| | |
Replica1 Replica2 Replica3Redis Cluster = 多 master 分片 + master-replica 高可用。
2. Cluster、主从、哨兵的区别
| 架构 | 核心能力 | 是否分片 | 是否自动故障转移 | 数据分布 |
|---|---|---|---|---|
| 主从复制 | 数据副本、读写分离 | 否 | 否 | 每个节点保存全量数据 |
| Sentinel | 单主高可用、自动切主 | 否 | 是 | 每个节点保存全量数据 |
| Cluster | 分片 + 高可用 | 是 | 是 | 不同 master 保存不同数据 |
主从和哨兵架构下,即使有多个从节点,也只是复制主节点的完整数据,无法解决单机容量瓶颈。Cluster 引入多个 master,每个 master 只负责一部分数据,因此可以横向扩展容量和吞吐。
3. 核心概念:16384 个 Slot
Redis Cluster 不直接把 key 映射到节点,而是引入了 哈希槽 slot:
key -> slot -> masterCluster 固定有 16384 个 slot,编号为 0 ~ 16383。
key 所属 slot 的计算方式:
slot = CRC16(key) % 16384如果直接使用 hash(key) % 节点数,节点数量变化时大量 key 的映射都会改变,迁移成本很高。使用 slot 后,key -> slot 固定,slot -> node 可调整,扩缩容时只需要迁移部分 slot。
slot 是 key 和节点之间的中间映射层,用来降低扩缩容的数据迁移成本。
4. 为什么是 16384 个 Slot?
16384 是 Redis Cluster 在分片粒度和元数据开销之间做的折中。
- slot 太少:迁移粒度太粗,扩缩容不灵活。
- slot 太多:节点之间通过 Gossip 传播 slot 信息的成本变高。
Redis Cluster 节点之间需要交换 slot 分布和节点状态,16384 个 slot 既能提供足够细的迁移粒度,又能控制集群元数据和网络通信开销。
5. Cluster 中 Master 负责什么?
每个 master 负责一部分 slot,以及这些 slot 下 key 的读写。
Master1: slot 0 ~ 5460
Master2: slot 5461 ~ 10922
Master3: slot 10923 ~ 16383Master 的职责包括:
- 处理自己负责 slot 范围内的 key 请求。
- 向自己的 replica 复制数据。
- 通过 Gossip 和其他节点交换集群状态。
- 参与故障检测和投票。
- 在扩缩容时迁入或迁出 slot。
6. 客户端如何路由请求?
Redis Cluster 通常要求客户端支持 Cluster 模式。客户端会缓存一张映射表:
slot -> node访问流程:
1. 客户端根据 key 计算 slot
2. 根据本地缓存找到负责该 slot 的 master
3. 向该 master 发送命令
4. 如果路由错误,根据 MOVED 或 ASK 重定向修正7. MOVED 重定向
如果客户端访问错节点,例如把 slot 8000 的请求发到了 Master1,但 slot 8000 实际属于 Master2,Master1 会返回:
MOVED 8000 192.168.1.12:6379含义:slot 8000 已经归 192.168.1.12:6379 管理,以后访问这个 slot 都应该去该节点。
客户端收到 MOVED 后应该更新本地 slot -> node 缓存,并把命令重试到正确节点。MOVED 是 永久重定向。
8. ASK 重定向
ASK 出现在 slot 迁移过程中。假设 slot 8000 正在从 Master1 迁移到 Master2:
Master1 --迁移 slot 8000--> Master2迁移过程中可能部分 key 还在 Master1,部分 key 已经在 Master2。如果客户端访问 Master1,但目标 key 已经迁到 Master2,Master1 会返回:
ASK 8000 192.168.1.12:6379客户端收到后,需要临时访问目标节点,先发送 ASKING,再执行真正命令。ASK 是 临时重定向,客户端不应该更新全局 slot 缓存。
9. MOVED 和 ASK 的区别
| 对比 | MOVED | ASK |
|---|---|---|
| 含义 | slot 已经迁移完成 | slot 正在迁移中 |
| 性质 | 永久重定向 | 临时重定向 |
| 是否更新客户端 slot 缓存 | 是 | 否 |
| 是否需要先发送 ASKING | 否 | 是 |
| 出现场景 | slot 稳定归属变化 | slot 迁移期间 |
一句话:
MOVED 是“以后都去新节点”,ASK 是“这次临时去新节点”。
10. 多 Key 命令限制
Redis Cluster 要求一个多 key 命令中的所有 key 必须属于同一个 slot。
例如:
MGET user:1 user:2如果两个 key 属于不同 slot,就会报错:
CROSSSLOT Keys in request don't hash to the same slot原因是 Redis Cluster 没有跨节点分布式事务协调机制,无法保证跨 slot 多 key 命令的原子性。受影响的包括 MGET、MSET、集合运算、Lua 脚本和 MULTI/EXEC 事务。
11. Hash Tag
如果 key 中包含 {},Redis 只对 {} 中的内容计算 slot。
user:{1001}:name
user:{1001}:age
user:{1001}:profile它们都会按 1001 计算 slot,因此会落到同一个 slot。
Hash Tag 不能滥用。如果大量 key 使用同一个 tag,会导致热点 slot、数据倾斜、单个 master 压力过大。正确做法是:只让确实需要一起操作的 key 使用相同 tag,比如同一用户、同一订单相关的小范围 key。
12. 节点间通信:Gossip 协议
Redis Cluster 没有中心节点,也不依赖 Sentinel。节点之间通过 Gossip 协议 交换集群状态。
Gossip 传播的信息包括节点是否在线、节点角色、slot 分布、复制关系、故障状态和配置纪元。
| 消息 | 作用 |
|---|---|
MEET | 让新节点加入集群 |
PING | 探测节点状态 |
PONG | 响应节点状态 |
FAIL | 广播节点确认下线 |
PUBLISH | 集群内发布消息 |
Gossip 让每个节点最终知道整个集群的拓扑、slot 分布和故障状态。
13. 故障检测:PFAIL 和 FAIL
Redis Cluster 的故障检测分两步:
PFAIL -> FAILPFAIL 表示疑似下线。如果某个节点在 cluster-node-timeout 时间内没有响应,当前节点会把它标记为 PFAIL。这只是单个节点自己的判断,类似 Sentinel 的主观下线。
FAIL 表示确认下线。当多个 master 都认为某节点不可达,并通过 Gossip 达成共识后,该节点会被标记为 FAIL,类似 Sentinel 的客观下线。
| 对比 | PFAIL | FAIL |
|---|---|---|
| 含义 | 疑似下线 | 确认下线 |
| 判断主体 | 单个节点 | 多个 master 共识 |
| 类比 Sentinel | 主观下线 | 客观下线 |
| 是否触发故障转移 | 不一定 | 会触发 replica 选举 |
14. 故障转移流程
假设 Master1 挂了,Replica1 是它的从节点:
1. 其他节点通过 Gossip 发现 Master1 不可达
2. Master1 被某些节点标记为 PFAIL
3. 多个 master 达成共识后,Master1 被标记为 FAIL
4. Replica1 发现自己的 master 已经 FAIL
5. Replica1 发起选举,向其他 master 请求投票
6. 获得多数 master 投票后,Replica1 晋升为新 master
7. Replica1 接管 Master1 原来负责的 slot
8. 集群广播新的 slot 归属
9. 客户端通过 MOVED 或更新后的 slot 缓存访问新 masterCluster 的故障转移不需要 Sentinel,它由集群节点自身完成。
15. Replica 晋升规则
当 master 有多个 replica 时,并不是随便选一个晋升。通常会考虑:
- replica 是否和旧 master 断开太久。
- replica 数据是否太旧。
- replica 优先级。
- 复制偏移量是否更靠前。
- 是否获得多数 master 投票。
目标是尽量选择数据最接近旧 master 的 replica 晋升。如果 replica 数据过旧,可能没有资格参与选举。
16. 为什么需要多数派投票?
Cluster 使用多数派投票,是为了避免多个 replica 同时晋升为 master。
3 个 master: majority = 2
5 个 master: majority = 3只有获得多数 master 投票的 replica,才能晋升为新 master。这样可以降低网络分区下多个节点同时成为 master 的风险。
17. Cluster 是否还需要 Sentinel?
不需要。Cluster 自带节点发现、Gossip 通信、故障检测、replica 晋升、slot 接管和 slot 归属传播。Sentinel 是单主多从架构中的高可用组件,而 Cluster 自身就是多主分片高可用架构。
18. Cluster 是否强一致?
不是。Redis Cluster 中 master 到 replica 的复制仍然是异步复制。
client -> master
master 执行写命令并返回成功
master 异步复制给 replica如果 master 写入成功后还没同步到 replica 就宕机,replica 晋升后这条写入可能丢失。因此 Cluster 解决的是分片和高可用,不是强一致。
19. 网络分区和脑裂
脑裂是指网络分区后,系统中短时间出现两个 master 都能接收写入。
分区 A:Old Master + 部分客户端
分区 B:多数 master + Replica + 部分客户端分区 B 中多数节点认为 Old Master 已经 FAIL,于是 Replica 晋升为 New Master。如果分区 A 中客户端还能写 Old Master,就会出现 Old Master 和 New Master 同时可写。
网络恢复后,Old Master 通常会被降级为 New Master 的 replica,它在脑裂期间接收的写入可能被覆盖或丢弃。Cluster 通过多数派投票、节点超时和故障转移机制缓解脑裂,但不能完全提供强一致保证。
20. cluster-require-full-coverage
cluster-require-full-coverage 控制 Cluster 是否要求所有 slot 都可用。
cluster-require-full-coverage yes如果配置为 yes,只要有任何 slot 不可用,整个集群都停止服务。如果配置为 no,只有不可用 slot 的请求失败,其他 slot 仍然可以服务。
21. 扩容流程
假设当前集群有 3 个 master:
M1: slots 0-5460
M2: slots 5461-10922
M3: slots 10923-16383现在新增 M4:
- M4 加入集群,默认没有 slot,不承担业务数据。
- 从 M1、M2、M3 迁移一部分 slot 给 M4。
- 把 slot 下的 key 从源节点迁移到目标节点。
- 迁移完成后,slot 正式归 M4 管理。
之后客户端如果还访问旧节点,会收到 MOVED。
22. 缩容流程
缩容和扩容相反:
1. 把待下线节点负责的 slot 迁移到其他 master
2. 确认该节点不再负责任何 slot
3. 从集群中移除该节点不能直接删除有 slot 的 master,否则它负责的 slot 会不可用。
23. Slot 迁移期间请求如何处理?
假设 slot 8000 从 A 迁到 B。
- key 还在 A:A 正常处理。
- key 已迁到 B:A 返回
ASK B,客户端临时去 B 执行。 - slot 完全迁移完成:A 返回
MOVED B,客户端更新 slot 缓存。
迁移中用 ASK,迁移完成用 MOVED。
24. Cluster 下 Pipeline
Cluster 下不能简单地把所有 pipeline 命令发到一个节点,因为不同 key 可能属于不同 slot、不同 master。
正确做法:
1. 客户端按 slot 或 node 对命令分组
2. 分别向对应 master 发送 pipeline
3. 收集多个节点返回结果
4. 合并结果
5. 处理 MOVED/ASK因此 Cluster pipeline 依赖客户端实现。
25. Cluster 下 Lua 和事务
Lua 脚本和事务要求涉及的所有 key 都在同一个 slot。
EVAL script 2 key1 key2如果 key1 和 key2 不同 slot,会报 CROSSSLOT。解决方式是使用 Hash Tag:
order:{1001}:stock
order:{1001}:lock26. Cluster 下读写分离
默认情况下写 master、读 master。有些客户端支持从 replica 读,但 replica 可能存在复制延迟。因此读 replica 适合对一致性要求不高的场景,不适合刚写完必须立刻读到的业务。
27. Cluster 和分布式锁
Cluster 下使用 Redis 分布式锁时,锁 key 只会落到某一个 master。如果这个 master 发生故障转移,仍然存在异步复制风险:
1. A 在 Master1 加锁成功
2. 锁还没复制给 Replica1
3. Master1 宕机
4. Replica1 晋升
5. B 又加锁成功此时 A 和 B 都可能认为自己持有锁。所以 Redis Cluster 不能从根本上保证强一致分布式锁。重要业务需要结合唯一 token、Lua 解锁、幂等控制、fencing token、数据库约束、状态机或 ZooKeeper/etcd。
28. 常见生产问题
热点 key
某个 key 被大量访问,会导致所有压力集中到一个 master。可以通过本地缓存、多级缓存、key 拆分、读写分离、限流降级解决。
热点 slot
大量 key 因 Hash Tag 落到同一个 slot,会导致单个 master 压力过大。需要避免滥用 Hash Tag,拆散热点 tag,或对热点业务二级分片。
BigKey
Cluster 不能把一个 BigKey 拆到多个节点。一个 BigKey 仍然只属于一个 slot 和一个 master。它会导致单节点内存压力大、网络传输慢、slot 迁移慢、删除阻塞、持久化和复制成本高。
Slot 分布不均
可以通过 CLUSTER NODES、CLUSTER SLOTS、节点内存监控、QPS 监控、慢查询和 bigkey 扫描排查。
扩容迁移风险
slot 迁移时会增加网络和 CPU 开销,客户端也可能收到 ASK/MOVED。生产建议低峰迁移、分批迁移、迁移前处理 BigKey,并监控延迟、QPS、网络和错误率。
29. Cluster 和代理分片对比
| 对比项 | Redis Cluster | 代理分片,如 Codis/Twemproxy |
|---|---|---|
| 路由位置 | 客户端路由 | 代理层路由 |
| 客户端感知 | 需要支持 Cluster | 客户端基本无感 |
| 性能路径 | 客户端直连 Redis | 多一层代理转发 |
| 高可用 | Cluster 内置 | 依赖代理和后端设计 |
| 复杂度 | 客户端复杂 | 代理层复杂 |
Cluster 是客户端感知的官方分片,代理模式是通过中间层屏蔽分片复杂度。
30. Cluster 和一致性哈希分片对比
客户端一致性哈希通常是客户端自己 hash key 到节点,Redis 节点之间彼此不知道。Redis Cluster 则是 Redis 节点知道彼此,维护 slot 元数据,支持 MOVED/ASK、slot 迁移和自动故障转移。
所以 Cluster 不只是简单 hash 分片,而是官方内建的分布式协议。
31. 重点问题
Redis Cluster 是怎么实现分片和高可用的?
Redis Cluster 通过 16384 个哈希槽实现数据分片。每个 key 会通过
CRC16(key) % 16384计算所属 slot,每个 master 负责一部分 slot。客户端会缓存 slot 到节点的映射,访问时先计算 key 的 slot,再把命令发到对应 master。如果访问错节点,Redis 会返回MOVED;如果 slot 正在迁移,可能返回ASK。Cluster 中节点之间通过 Gossip 协议交换节点状态、slot 分布和故障信息。每个 master 可以配置 replica。当某个 master 长时间不可达时,会先被标记为
PFAIL,之后多个 master 达成共识后标记为FAIL。该 master 的 replica 会发起选举,获得多数 master 投票后晋升为新 master,并接管原 master 的 slot。Cluster 支持水平扩容,新增 master 后可以迁移部分 slot;缩容时要先迁走 slot 再移除节点。它的限制是多 key 命令、事务和 Lua 要求 key 在同一个 slot,可以通过 Hash Tag 解决。需要注意的是,Cluster 复制仍然是异步的,因此它解决的是分片和高可用,不保证强一致。
32. 总结
1. Cluster 用 16384 个 slot 分片
2. key 通过 CRC16(key) % 16384 找 slot
3. 每个 master 负责一部分 slot
4. 客户端缓存 slot -> node
5. MOVED 是永久重定向,ASK 是迁移中临时重定向
6. 多 key 必须同 slot,否则 CROSSSLOT
7. Hash Tag 可以让相关 key 落到同一个 slot
8. 节点之间用 Gossip 通信
9. PFAIL 是疑似下线,FAIL 是确认下线
10. master 挂了,replica 投票晋升并接管 slot
11. 扩容缩容本质是迁移 slot
12. Cluster 异步复制,不保证强一致Redis Cluster 的主线是
key -> slot -> master做分片,MOVED/ASK做路由修正,Gossip做节点通信,PFAIL/FAIL + 投票做故障转移,slot 迁移做扩缩容;它解决容量和可用性,但不解决强一致。
