返回首页

Redis 架构篇5.3: Cluster 集群基础

适用版本:Redis 7.2.x

当业务规模继续增大,单个 Redis 主库哪怕配了多个从库,也还是会遇到一个核心瓶颈:

  • 内存容量有上限;
  • 单机 CPU 有上限;
  • 单主写入能力也有上限。

这时候,仅靠主从复制和 Sentinel 已经不够了。因为它们解决的是高可用,而不是横向扩容

Redis Cluster(集群)就是 Redis 官方提供的分布式分片方案。它把数据拆散到多个主节点上,每个主节点再带自己的副本,从而同时解决两类问题:

  1. 容量扩展:数据不再塞进一台机器;
  2. 高可用:每个主节点都有副本,主故障时可以自动切换。

这篇文章会重点讲清楚 Cluster 的基础模型:哈希槽、节点角色、请求路由、重定向机制、创建方式与使用边界。只要把这些底层逻辑搞明白,后面再学扩缩容、迁槽、故障处理就会顺很多。


一、Redis Cluster 解决的核心问题是什么

先看一个问题。

如果只有 Sentinel 模式,即使你有:

  • 1 个主库
  • 2 个从库
  • 3 个哨兵

你仍然只有一个写主。数据再多、写入再高,压力还是集中在一个主节点上。

而 Redis Cluster 的目标,是把数据和流量分散到多个主节点

1. 从“单主复制”变成“多主分片”

Cluster 不是一个主库加很多从库,而是:

  • 多个主节点共同组成一个逻辑集群;
  • 每个主节点负责一部分数据;
  • 每个主节点再有自己的副本,用于故障转移。

2. 同时兼顾扩展与可用

因此 Redis Cluster 可以理解为:

分片能力 + 副本高可用能力 的组合。


二、Cluster 的整体架构图景

一个最小可用的 Redis Cluster,通常至少是 3 主 3 从。

                  +----------------------+
                  |        Client        |
                  |  感知集群拓扑并路由请求 |
                  +----------+-----------+
                             |
        +--------------------+--------------------+
        |                    |                    |
        v                    v                    v
   +---------+         +---------+         +---------+
   | Master1 |         | Master2 |         | Master3 |
   |槽位0~5k |         |槽位5k~10k|        |槽位10k~16k|
   +----+----+         +----+----+         +----+----+
        |                   |                   |
        v                   v                   v
   +---------+         +---------+         +---------+
   |Replica1 |         |Replica2 |         |Replica3 |
   +---------+         +---------+         +---------+

在这个结构里:

  • 每个 master 负责一部分槽位和数据;
  • 每个 replica 复制对应主节点的数据;
  • 客户端不再只盯住单台 Redis,而是要理解整个集群拓扑。

这也是 Redis Cluster 和 Sentinel 最大的使用差异之一:

Cluster 客户端必须具备集群路由能力。


三、哈希槽:Cluster 的核心设计

Redis Cluster 没有采用“直接按节点数量做哈希”的方式,而是引入了 16384 个哈希槽(hash slots)

1. 什么是哈希槽

可以把它理解成:

  • 整个集群预先划分好 16384 个桶;
  • 每个 key 先映射到某个槽;
  • 槽再归属于某个主节点。

例如:

key -> CRC16(key) % 16384 -> slot -> 某个 master 节点

2. 为什么要引入槽位,而不是直接 key -> node

因为这样做有明显好处:

  • 节点扩缩容时,迁移的是槽位,不是重新整体洗牌;
  • 集群拓扑变化更容易管理;
  • 数据迁移粒度更清晰。

3. 一个直观例子

假设:

  • Master1 负责槽位 0 ~ 5460
  • Master2 负责槽位 5461 ~ 10922
  • Master3 负责槽位 10923 ~ 16383

如果 key user:1001 经过计算落在槽位 8200,那它就归 Master2 负责。

所以 Redis Cluster 的本质不是“key 落在哪台机器”,而是:

key 先落在哪个槽,再由槽决定归属节点。


四、节点角色与副本关系

1. 主节点负责槽位

只有主节点负责持有槽位并处理该槽位的数据写请求。

2. 从节点复制主节点

每个主节点都可以有一个或多个副本。副本默认复制主节点数据,用于高可用切换。

3. 从节点不负责槽位归属

从节点本身不是槽位拥有者,它主要承担:

  • 数据副本存储;
  • 故障时的主从切换候选;
  • 某些读场景下可辅助分流(但要谨慎处理一致性)。

4. Cluster 中也有自动故障转移

如果某个主节点失效,且它有可用副本,集群会尝试让对应副本提升为新的主节点,继续接管原来那批槽位。

所以 Cluster 并不是不要复制,而是:

  • 主节点之间负责分片;
  • 主从之间负责高可用。

五、客户端为什么必须“懂集群”

在单机 Redis 或 Sentinel 模式下,客户端通常只要找到当前主库即可。

但在 Cluster 模式下,客户端面对的是多个主节点,必须知道:

  • 某个 key 对应哪个槽位;
  • 这个槽位当前在哪个节点上;
  • 如果拓扑变化了,如何刷新路由表;
  • 遇到 MOVEDASK 重定向时怎么处理。

这意味着普通的单机 Redis 客户端不能直接无脑连接 Cluster。

一个常见误区

很多新手以为:

Cluster 就是“多台 Redis 放一起”,我连任意一台发命令就行。

其实不对。真正正确的理解是:

客户端需要感知整个槽位与节点的映射关系。


六、请求路由:为什么会出现 MOVED 和 ASK

1. MOVED

如果客户端把某个 key 的请求发到了错误节点,而该节点知道这个槽位已经正式归属其他节点,它会返回类似:

-MOVED 8200 192.168.10.12:6379

含义是:

  • 槽位 8200 不在我这里;
  • 它正式属于 192.168.10.12:6379
  • 你应该更新路由并去那边访问。

2. ASK

在槽位迁移过程中,一个槽可能处于“正在搬家”的过渡状态。这时节点可能返回:

-ASK 8200 192.168.10.12:6379

它的语义和 MOVED 不一样:

  • 这不是长期归属变更;
  • 而是一次临时引导;
  • 客户端本次请求先去目标节点,并带 ASKING

3. 为什么要区分两种重定向

因为它们代表不同阶段:

  • MOVED:槽位已经迁完,路由应长期更新;
  • ASK:槽位还在迁移中,本次请求临时转发即可。

这也是 Cluster 扩缩容时必须理解的关键基础。


七、跨槽问题:为什么有些多 key 命令会报错

Redis Cluster 里一个非常典型的问题就是:

CROSSSLOT Keys in request don't hash to the same slot

1. 原因是什么

因为多 key 操作如果涉及不同槽位,就无法保证在一个节点上完成。

典型场景包括:

  • MGET key1 key2
  • SUNION set1 set2
  • DEL key1 key2 key3
  • Lua 脚本访问多个不同槽位的 key

2. 为什么 Redis Cluster 不支持任意跨节点原子操作

因为 Cluster 的目标是高性能分片,而不是分布式事务系统。让不同主节点之间做复杂协同,会显著增加系统复杂度和性能成本。

3. 如何解决:Hash Tag

Redis Cluster 提供了 Hash Tag 机制。

如果 key 中带有同一对花括号 {} 包裹的内容,那么计算槽位时只会对花括号里的部分做哈希。

例如:

order:{1001}:info
order:{1001}:items
order:{1001}:status

这三个 key 会落到同一个槽位,于是你就可以更容易地对它们做多 key 操作。

4. 什么时候适合用 Hash Tag

适合:

  • 同一业务实体的多个 key 需要落在一起;
  • 明确存在多 key 操作需求;
  • 需要局部事务或局部 Lua 脚本操作。

但不要滥用,否则会导致数据过度集中,破坏分片均衡。


八、Redis Cluster 的最小创建方式

通常可以用 redis-cli --cluster 来快速创建测试集群。

假设你已经启动 6 个实例:

  • 7000
  • 7001
  • 7002
  • 7003
  • 7004
  • 7005

每个实例都要至少开启:

cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

然后执行:

redis-cli --cluster create \
127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \
127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
--cluster-replicas 1

这个命令的含义是:

  • 用 6 个节点创建一个集群;
  • 每个主节点分配 1 个副本;
  • 最终会形成 3 主 3 从。

创建完成后,可以检查集群信息:

redis-cli -p 7000 cluster nodes
redis-cli -p 7000 cluster info

九、常用 Cluster 命令

1. 查看集群整体状态

127.0.0.1:7000> CLUSTER INFO

常关注字段:

  • cluster_state:是否为 ok
  • cluster_slots_assigned:是否分配完 16384 个槽;
  • cluster_known_nodes:已知节点数量;
  • cluster_size:主节点数量。

2. 查看节点拓扑

127.0.0.1:7000> CLUSTER NODES

可以看到:

  • 每个节点 ID;
  • 角色是主还是从;
  • 从属关系;
  • 槽位分布;
  • 当前连接状态。

3. 查看某个 key 属于哪个槽

127.0.0.1:7000> CLUSTER KEYSLOT user:1001
(integer) 8200

这个命令很适合排查跨槽问题。

4. 查看某个槽归谁管理

127.0.0.1:7000> CLUSTER SLOTS

能看到槽位范围与节点地址映射关系。

5. 使用集群模式连接客户端

redis-cli -c -p 7000

-c 表示开启集群模式,这样 redis-cli 才能自动处理 MOVED 和部分路由跳转。


十、Cluster 的高可用是怎么实现的

Redis Cluster 内部也有故障检测和主从切换能力。

1. 节点之间会互相通信

Cluster 节点通过集群总线交换状态信息,包括:

  • 节点存活情况;
  • 槽位归属;
  • 故障报告;
  • 复制关系。

2. 主节点故障时,副本可提升

如果某个主节点被认为故障,并且存在合格副本,则副本会尝试发起故障转移,成为新的主节点,接管原有槽位。

3. 仍然有异步复制边界

和普通主从一样,Cluster 的副本复制本质上仍然是异步的,所以在故障切换瞬间仍可能损失最近少量未复制完成的数据。

所以需要清楚:

Cluster 提供的是高可用能力,不是强一致分布式数据库语义。


十一、Cluster 的优点与限制

1. 优点

  • 支持水平扩容;
  • 每个主节点分担部分内存与流量;
  • 自带副本高可用能力;
  • 官方原生支持,生态成熟。

2. 限制

  • 客户端必须支持 Cluster;
  • 多 key 操作受槽位限制;
  • Lua、事务等操作一般要求 key 落在同一槽;
  • 运维复杂度高于单机和 Sentinel;
  • 故障切换期间仍可能有短暂不可用或少量数据丢失。

3. 适用场景

Cluster 更适合:

  • 数据规模已经超过单机容量;
  • 需要多主分片扩容;
  • 能接受客户端集群化改造;
  • 对高性能 KV 分布式缓存有明确需求。

十二、常见问题

1. Redis Cluster 和 Sentinel 有什么本质区别?

可以简单理解为:

  • Sentinel:解决单主架构的自动故障切换;
  • Cluster:解决多主分片 + 副本高可用。

如果只是单实例高可用,Sentinel 通常够用;如果单机容量已经不够,才需要 Cluster。

2. 为什么 Redis Cluster 是 16384 个槽,而不是更多?

你可以把它理解为一个在路由粒度、元数据大小、管理复杂度之间做出的平衡设计。对大多数业务场景来说,16384 个槽已经足够细。

3. 为什么我连接某个节点时会收到 MOVED

因为你请求的 key 不归当前节点负责。正确做法是:

  • 使用支持 Cluster 的客户端;
  • 或者用 redis-cli -c 连接测试。

4. Cluster 能不能完全避免单点问题?

不能完全避免,但能显著降低单点影响。因为每个主节点仍然可能故障,只是它有副本,可以在故障时接管槽位。

5. 为何多 key 命令经常报跨槽错误?

因为这些 key 不在同一槽位。要么重新设计 key,要么用 Hash Tag 把相关 key 放进同槽。

6. 从节点能不能直接承接所有读请求?

可以做读扩展,但要谨慎,因为复制是异步的,存在读到旧数据的可能。对一致性要求高的场景不能想当然地“写主读从”。


十三、实践建议

1. 先想清楚是不是必须上 Cluster

Cluster 不是默认最佳答案。它带来扩展能力,也引入了更高的客户端和运维复杂度。如果数据规模、流量规模还没到单机瓶颈,Sentinel 可能更简单。

2. 提前设计 key 与槽位策略

尤其是:

  • 哪些 key 可能需要多 key 操作;
  • 哪些业务实体适合用 Hash Tag 聚合;
  • 如何避免热点过度集中到单槽。

3. 客户端务必使用原生支持 Cluster 的 SDK

不要在业务里自己手写槽位路由逻辑,除非你非常清楚全部细节。

4. 监控不只看节点,还要看槽位分布

Cluster 的问题很多不是“某台机器挂了”,而是:

  • 槽位迁移不均;
  • 热点槽位偏斜;
  • 某个主节点压力异常;
  • 节点间网络抖动。

5. 为后续扩缩容预留心智模型

只要你记住“Cluster 是按槽位管理数据”,后面学迁槽、扩容、缩容、故障转移就会容易很多。


十四、小结

学习 Redis Cluster,最重要的是先建立下面这套认知:

  1. Cluster 不是单主复制,而是多主分片架构;
  2. 数据通过 CRC16(key) % 16384 映射到哈希槽,再由槽位归属主节点;
  3. 每个主节点再配副本,用于故障切换;
  4. 客户端必须理解槽位路由,并正确处理 MOVED / ASK
  5. 多 key 操作通常要求 key 落在同一槽位,必要时可借助 Hash Tag。

如果把这些基础概念掌握住,Redis Cluster 就不会再只是一个“很复杂的分布式名词”,而会变成一个清晰的结构化系统。后续再看集群扩容、缩容、迁槽和故障处理时,你会更容易理解每一步到底在做什么。


📝 版权声明:本文为原创技术博客,转载请注明出处。

如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!

上一篇

Redis 架构篇5.2:Sentinel 哨兵机制

下一篇

Redis 架构篇5.4: 集群扩缩容与故障处理