Redis Cluster 集群模式
Redis Cluster 集群模式
一、什么是 Redis 集群
**集群(Cluster)**是一组相互独立的、通过高速网络互联的计算机,它们构成一个组,以单一系统的模式对外提供服务。
二、集群 vs 哨兵:核心区别
这是最容易混淆的两个概念,先理清定位:
| 维度 | Sentinel 哨兵 | Cluster 集群 |
|---|---|---|
| 解决什么问题 | 高可用 —— 主库宕机自动故障转移 | 数据分片 + 高可用 —— 超大数据集水平扩展 |
| 数据分布 | 所有节点保存全量数据 | 数据打散到各节点,每个节点只存子集 |
| 容量上限 | 受限于单机内存 | 理论上无限水平扩展 |
| 最小部署 | 1 主 + N 从 + M 哨兵 | 至少 6 个节点(3 主 3 从) |
| 中心节点 | 有(Master 角色) | 无中心结构,所有节点地位平等 |
| 通信协议 | 哨兵 → 主从:PING/PUBLISH | 节点之间:Gossip 协议 |

简单记忆:
- 只要数据量单机能装下,只需要高可用 → 用 Sentinel
- 数据量太大单机装不下 → 必须用 Cluster
三、Redis Cluster 核心特性
3.1 架构概述
- 版本要求:Redis 3.0 开始引入 Cluster 模式
- 拓扑结构:无中心化(decentralized),没有专门的代理或路由节点
- 节点关系:每个节点都和其他所有节点保持 TCP 连接
- 官方推荐:至少 6 个节点才能保证高可用——即 3 主 3 从
- 元数据同步:节点间通过 Gossip 协议交换状态信息
- 数据分布:整个数据集按 16384 个槽位(slot) 分散到各主节点
3.2 槽位分配机制(Hash Slot)
这是 Redis Cluster 最核心的设计。
为什么是 16384 个槽?
| 问题 | 答案 |
|---|---|
| 槽位数量 | 16384(即 $2^{14}$) |
| 为什么不是更多? | 槽位信息通过 Gossip 协议传播,太多会浪费带宽。16384 占用仅 2KB(16 bit × 16384 / 8),心跳包开销极小 |
| 为什么不是更少? | 太少会导致数据分布不够均匀,迁移时粒度过粗影响性能 |
分配规则
- 整个键空间被划分为 0 ~ 16383 共 16384 个槽位
- 每个主节点负责其中一部分槽位的范围(如 Node A 负责 0
5460, B 负责 546110922, C 负责 10923~16383) - 当客户端操作某个 key 时,先用
CRC16(key) % 16364计算该 key 属于哪个槽位 - 再根据槽位到节点的映射表,找到对应的主节点进行读写
- 如果请求到了不负责该槽位的节点,该节点会返回
MOVED重定向错误,引导客户端访问正确的节点
槽位迁移
Cluster 支持在线的槽位重新分配(resharding):
1 | CLUSTER SETSLOT <slot> IMPORTING <node-id> # 目标节点准备导入 |
3.3 Gossip 协议
节点之间通过 Gossip 协议交换以下元数据:
- 节点状态(online / fail / pfail)
- 槽位分配信息
- 其他节点的已知状态
工作方式:每秒随机选择几个节点发送 ping/pong 消息,逐步将信息扩散到全网。虽然消息有延迟,但保证了最终一致性。
四、高可用保障
故障检测与切换流程
sequenceDiagram
participant C as 客户端
participant P as 主节点A
participant S1 as 从节点A1
participant S2 as 从节点A2
participant O as 其他主节点
Note over P,O: 定期 PING/PONG 心跳检测
P->>O: PING (心跳)
O-->>P: PONG (响应)
Note over P: ⚠️ 主节点 A 无响应
O->>O: 标记 A 为 PFAIL (主观下线)
O->>S2: 广播 A 的 PFAIL 状态
Note over S1,S2: 半数以上节点确认 A 下线
S1->>S1: 将 A 标记为 FAIL (客观下线)
Note over S1: 发起选举
S1->>S2: 请求投票 (VOTE)
S2-->>S1: 投票同意
S1->>S1: 成为新主节点
Note over S1: 更新槽位映射
S1->>O: 广播新的槽位分配
O-->>C: MOVED 重定向到新主节点
关键要点:
- 主观下线(PFAIL):某个节点发现目标节点超时未响应(
cluster-node-timeout配置) - 客观下线(FAIL): 超半数主节点确认该节点下线
- 选举:从节点发起投票,获得多数票者成为新主节点
- 通知更新:新主节点广播自身角色变更,其他节点更新路由表
客户端重定向
当客户端访问的槽位不在当前节点时:
| 错误类型 | 含义 | 处理方式 |
|---|---|---|
MOVED |
槽位已永久迁移到其他节点 | 更新本地槽位缓存,后续直连正确节点 |
ASK |
槽位正在迁移中,部分 key 还在原节点 | 临时去原节点查询一次 |
大多数 Redis 客户端驱动(Jedis、Lettuce、Redisson 等)都已内置 Cluster 支持,自动处理重定向。
五、实战:搭建一个 3 主 3 从集群
5.1 创建实例目录
1 | # 在不同端口创建 6 个 Redis 实例(7000~7005) |
5.2 启动所有实例
1 | for port in 7000 7001 7002 7003 7004 7005; do |
5.3 创建集群
1 | # --cluster-replica 1 表示每个主节点自动分配 1 个从节点 |
执行后系统会自动:
- 将 16384 个槽位平均分配给 3 个主节点(7000/7001/7002)
- 为每个主节点分配一个从节点(7003→7000, 7004→7001, 7005→7002)
5.4 验证集群状态
1 | # 查看集群信息 |
注意:使用
-c参数启用集群模式,客户端会自动处理MOVED重定向。
六、常用命令速查
1 | # === 集群管理 === |
七、注意事项
- 不支持多 key 操作跨槽:
MGET、MSET、SUNION等多 key 命令要求所有 key 必须落在同一个槽位。可以使用 Hash Tag{...}强制相关 key 落在同一槽位(如user:{1001}:profile和user:{1001}:orders会落到同一个槽) - 事务限制:
MULTI/EXEC事务中的命令必须作用于同一槽位 - 数据库限制:集群模式下只能使用
db 0 - Pipeline 优化:客户端应尽量使用 Pipeline 批量操作减少网络往返
- 扩容建议:提前规划槽位分配,尽量避免频繁 resharing;生产环境建议使用运维工具(如 Redis Insight、Codis)辅助管理
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 优秀的螺丝工!
评论