首页 / Redis 入门教程 / 28. Redis 集群 Cluster 基础

Redis 入门教程

28. Redis 集群 Cluster 基础

本教程共 40 篇 · 第 28 篇 · 更新于 2026-08-02

Cluster集群分片哈希槽hash slotMOVED高可用

28. Redis 集群 Cluster 基础

主从复制 + 哨兵解决了「高可用」,但没有解决容量与写性能的上限——所有数据仍然在一台主节点上。当数据量超过单机内存,或写 QPS 超过单机处理能力时,就需要把数据**分片(shard)**到多台机器上,这就是 Redis Cluster(集群)

Redis Cluster 是 Redis 官方提供的分布式方案,它把数据自动切分到多个分片,每个分片又可由「一主多从」组成,从而同时获得可扩展性高可用。码上学先把集群的核心模型讲明白,下一章(29)再动手搭建。

本节目标

  • 理解 Redis Cluster 用 16384 个哈希槽 做数据分片。
  • 掌握键到槽的映射公式 CRC16(key) mod 16384,以及 hash tag 的用法。
  • 理解集群下「多键操作必须同槽」的限制。
  • 理解 MOVED 与 ASK 两种重定向。
  • 了解集群的节点模型、规模上限与主要限制。

哈希槽(Hash Slot):分片的单元

Redis Cluster 把整个键空间划分为 16384 个哈希槽(hash slot)。集群中的每个主节点负责其中一部分槽。数据落在哪个槽,就由负责那个槽的主节点存储和服务。

  • 集群稳定时(没有正在迁移槽),一个槽只由一个主节点负责(该主节点可带一个或多个从节点用于故障转移和读扩展)。
  • 16384 这个数量,给集群规模设定了理论上限 16384 个主节点;但官方建议实际集群规模控制在约 1000 个节点以内,超过后 gossip 通信开销会明显增大。

键如何映射到槽

基础算法(来自官方 cluster-spec)非常简单:

HASH_SLOT = CRC16(key) mod 16384

其中 CRC16 采用 XMODEM(CRC-16/ACORN)参数,取输出 16 位中的 14 位参与取模,因此结果是 0~16383 之间的整数。实践中你不需要手算,Redis 提供了 CLUSTER KEYSLOT 命令直接查询:

127.0.0.1:7000> CLUSTER KEYSLOT user:1000
(integer) 349

这表示键 user:1000 落在第 349 号槽。你也可以查看某个槽里当前有多少键:

127.0.0.1:7000> CLUSTER COUNTKEYSINSLOT 349
(integer) 12

Hash Tag:让相关键落在同一槽

分片带来一个限制:跨槽的多键操作(如 MSETSUNION、事务)不被支持。但现实中我们经常需要把一组相关键放在一起操作,例如 user:1000:followinguser:1000:followers 想做交集。

为此 Redis Cluster 引入了 hash tag(哈希标签):如果键里包含 {...} 这样的模式,只有花括号之间的子串会参与 CRC16 计算,其余部分被忽略。于是:

127.0.0.1:7000> CLUSTER KEYSLOT {user1000}.following
(integer) 273
127.0.0.1:7000> CLUSTER KEYSLOT {user1000}.followers
(integer) 273

两个键都只哈希 user1000 子串,因此落到同一个槽(273),就可以放心地做多键操作了。

hash tag 的边界规则(避免踩坑):

  • foo{}{bar}:第一个 { 后面紧跟 },中间没有字符,则整个键照常哈希(不生效)。
  • foo{{bar}}zap:哈希 {bar(第一个 { 到第一个 } 之间的内容)。
  • foo{bar}{zap}:只取第一个有效匹配 bar

提示(Redis 8.x 新特性):从 Redis 8.0 起,接受 glob 模式的命令(KEYSSCANSORT)在模式「只属于单个槽」时会做优化——例如 SCAN 0 MATCH {abc}* 能识别 hash tag,只扫描 abc 对应的那个槽,而非遍历全部 16384 个槽,大幅减少集群下的扫描开销。

客户端路由与 MOVED 重定向

集群下,客户端可以往任意节点发请求。收到请求后,节点会检查目标键所属槽是否由自己负责:

  • 是 → 直接处理,返回结果。
  • 否 → 返回 MOVED 重定向错误,告诉客户端「这个槽归谁管」。
127.0.0.1:7000> GET x
(error) MOVED 3999 127.0.0.1:6381

错误信息包含「槽号(3999)」和「真正负责该槽的节点地址(127.0.0.1:6381)」。客户端应当改用这个地址重新发起请求。成熟的集群客户端会缓存「槽 → 节点」映射表,之后直接命中正确节点,避免每次都绕一次 MOVED。

一个合格的 Redis Cluster 客户端必须能处理 MOVED 重定向;否则它根本算不上完整的集群客户端。

槽迁移与 ASK 重定向

当集群扩缩容、需要把某些槽从一个节点迁到另一个节点时,迁移是在线进行的:底层是把槽里的键逐个从源节点搬到目标节点。迁移过程中,该槽处于「中间态」,此时访问会触发 ASK 重定向

  • 源节点把该槽标记为 MIGRATING,目标节点标记为 IMPORTING
  • 客户端访问正在迁移的键时,若键已迁走,源节点返回 -ASK <slot> <target-ip:port>
  • 客户端需要先对被重定向的节点发送一条 ASKING 命令「打声招呼」,再发真正的请求,目标节点才会处理这个本不属于自己的 IMPORTING 槽的请求。
127.0.0.1:7000> GET migratingkey
(error) ASK 8 127.0.0.1:7001

与 MOVED 的区别在于:ASK 是一次性、临时性的(仅对当前这个键这次请求有效),客户端不应因此更新自己的槽映射表;而 MOVED 是稳定重定向,客户端应当更新缓存。完整的集群客户端同样必须正确处理 ASK。

节点模型与故障转移

Redis Cluster 里每个分片由「1 主 + N 从」构成:

  • 主节点负责一部分槽、处理对应写请求。
  • 从节点复制其主节点,在主节点故障时通过集群内部的选举被提升为新主,接管槽,实现分片级高可用(无需额外哨兵,集群自带故障转移)。

节点之间通过 gossip 协议交换状态(谁在线、谁负责哪些槽、谁挂了),最终全网达成一致。当某个主节点被多数节点判定失效,它的一个从节点会被提升。注意:集群要能完成故障转移,同样需要满足「多数派」——如果超过半数的主节点同时不可用,集群会拒绝写入(进入失败状态),以保护数据安全。

集群的主要限制

因为数据被分片,集群模式相比单机有一些约束,码上学提醒你提前知晓:

  1. 多键操作必须同槽:跨槽的 MGETSUNION、事务、Lua 脚本等不被支持(除非用 hash tag 把它们约束到同一槽)。
  2. 只支持一个数据库:集群下 SELECT 不可用,所有键都在 db 0。
  3. 键是分片的最小粒度:不能把一个超大的键(如一个几十 GB 的有序集合)再切分,超大数据集要靠合理设计多个键。
  4. 客户端必须支持集群协议:要用支持 MOVED/ASK 的集群客户端,普通单机客户端连集群会频繁报错。

小结

  • Redis Cluster 用 16384 个哈希槽 分片,键经 CRC16(key) mod 16384 决定归属。
  • hash tag{...})可强制相关键同槽,从而支持多键操作。
  • 访问错节点会得到 MOVED(稳定重定向,应更新映射)或 ASK(迁移中的临时重定向,需先 ASKING)。
  • 每个分片「主 + 从」,靠 gossip + 选举实现分片内自动故障转移,无需哨兵。
  • 集群限制:多键须同槽、仅 db 0、需集群客户端。

提示:官方 redis.io 下载页另将 8.8 标注为 “Latest stable”,而 GitHub 上的最新发布 tag 为 8.10.0。集群核心机制(16384 槽、CRC16 映射、MOVED/ASK)在 8.x 中保持稳定,且 8.0 起新增了 glob 模式的单槽扫描优化,本文以 8.10.0 为基线版本。