云霞资讯网

为什么 Redis Cluster 要设计 16384 个槽?答案比你想的聪明

大家好,我是 31 岁的小米,一个热爱折腾技术、喜欢一边踩坑一边做咖啡的程序员。前段时间陪朋友准备 Java 社招面试



大家好,我是 31 岁的小米,一个热爱折腾技术、喜欢一边踩坑一边做咖啡的程序员。

前段时间陪朋友准备 Java 社招面试,他问了我一句:

“小米,Redis 的哈希槽到底是怎么回事?我每次面试都被问,答得似懂非懂……”

我一听,熟悉的面试 PTSD 猛地从脑子里蹿出来,仿佛又看到那年面试官微微抬起眼镜、露出“我就等你卡壳”的表情。于是我拍了拍他肩膀说:

“兄弟,关于 Redis 哈希槽,我给你讲个故事 —— 听完你不仅懂了,还能反问面试官。”

先从一个小镇说起:16384 个房间的城市

想象一下,有一座神奇的小镇。镇上有 16384 间房间,编号从 0 到 16383。每一个房间,代表着 Redis Cluster 的一个“哈希槽”(Hash Slot)。

Redis 官方设计 Redis Cluster 时,决定不采用一致性哈希(像很多分布式系统那样),而是采用这种固定槽位机制。为什么?

因为一致性哈希迁移数据太麻烦,而槽位更像是房屋产权登记:只要告诉你“第 1000-2000 号房子属于 A 节点”,你就能快速定位。

这个世界观建立好之后,你会发现:

数据不直接分配给节点

而是分配给槽位(Slot)

然后槽位再分配给不同的 Redis 节点

换句话说:

Redis Cluster 的本质不是“节点分数据”,而是“节点分槽,槽分数据”。

这一句话,面试官听了都得点头。

那数据怎么知道自己属于哪个槽?

继续想象:你把一把钥匙(Redis 的 Key)扔进这个小镇。小镇有一个超级强的“分拣机”,叫 CRC16 算法。

它会对 key 做一次 CRC16 运算,得到一个数值。然后对这个数值进行取模:

slot = CRC16(key) % 16384

这个公式就是 Redis 哈希槽分配的核心规则。比如:

key = "user:1" → 可能落到槽 8120

key = "order:2023" → 可能落到槽 1520

然后Redis 就会根据槽位编号把请求路由到对应节点。你可以把它理解为:

这个世界上没有乱放的行李,每一个 key 都会分配到某个固定编号的房间里。

有序、有逻辑、不乱,Redis 就像是老城区里经验丰富的管理员。

问题来了:如果一个“大 key 族”必须放一起,那怎么办?

朋友听到这里问:

“那多个 key 想落到同一个槽,有办法吗?比如 Redis Pipeline 或 Lua 想用多个 Key 操作一个功能。”

我说:当然有,Redis 已经帮你想好办法了,那就是:使用 {} 哈希标签(Hash Tag)

你只需要把你想固定的部分放进大括号里,比如:

user:{1001}:profile

order:{1001}:list

cart:{1001}

无论 key 前后缀多长,Redis 只会对 {1001} 做哈希。于是,这几个 key 一定分配到同一个槽!原因是:

CRC16("user:{1001}:profile") = CRC16("{1001}")

在集群模式下,多个 key 必须落在同一个槽才能原子执行(如 MGET/MSET 或 Lua 脚本)。这也是为什么 Redis 必须提供哈希标签机制。

一句话总结:

{} 内的内容决定槽位,外面的不参与计算。

面试时能讲到这一点,面试官的眼镜会滑下来一点。

为什么是 16384?不是 1024 也不是 65536?

这个问题面试官也爱问。我带你走进 Redis 作者 antirez 的脑子:

1、太小不行(比如 1024)

容易导致扩容时槽太粗,数据迁移“块度”太大,不够灵活。

2、太大也不行(比如 65536)

主要是两个原因:

心跳消息变大。Redis Cluster 中节点之间要同步槽位映射表,槽太多会导致 Gossip 协议包超大。

性能浪费。过多槽位会导致维护成本上升,收益却不明显。

综合各种权衡,16384 是最佳选择:

足够细

映射表不会太大

迁移粒度合适

性能稳定

你完全可以把这个记成:

Redis 里,16384 是经过大量工程实战验证过的“甜蜜点”。

Redis 集群扩容时:槽是怎么搬家的?

这部分属于回答面试官时“加分项”。假设你现在有:

Node A:槽 0~5461

Node B:槽 5462~10922

Node C:槽 10923~16383

要新增一个节点 Node D,该怎么迁移槽?Redis 的做法是:

先把要迁移的槽位标记为“导入中”或“导出中”

槽位内的数据逐个迁移

迁移过程中,客户端如果访问数据:

可能被重定向到源节点

也可能被重定向到目标节点

全部迁移完成后,更新整个集群槽位映射表

整个过程依赖两个关键命令:

CLUSTER SETSLOT

MIGRATE

这套流程的本质是:不会让你因为迁移而中断服务。

只要你能把上面的流程讲出来,面试官心里会默默给你加分。

“重定向”机制:为什么我访问 Redis 会收到 MOVED 或 ASK?

当你访问一个 key,却访问到了错误节点时,Redis 会告诉你:

1、MOVED

表示:“兄弟,你访问错地方了,这个槽已经永久搬到另一个节点了。”

MOVED 会让客户端 更新本地槽位映射表,以后别再访问错了。

2、ASK

表示:“这个 key 正在搬家,但现在还没搬完,你暂时去另一个节点拿吧。”

这是迁移过程中的临时状态。不会更新客户端本地映射表。

你可以把 MOVED 想象成:房东永久搬家了,而 ASK 是:房东正在搬家中,你暂时去新家找他。

如果你能把这个比喻讲给面试官,他会心一笑。

为什么 Redis Cluster 非要用槽?

说个大白话,如果不用槽,会怎样?

扩容/缩容时,需要遍历所有 key

迁移成本巨大

每个 key 的分布无法控制

多 key 操作几乎无法保证落在一起

Redis 的槽机制让:

数据分布均衡

集群扩缩容简单

路由精确

多 key 操作可以指定落同槽

整个 Redis Cluster 保持高性能

这就是 Redis 哈希槽存在的根本原因。

面试官最爱问的8个 Redis 哈希槽题目(附完美答法)

我送你一个小抄,你随便背一个,面试稳得不行。

1、Redis 为什么使用 16384 哈希槽?

因为槽位太少不够细、太多会增加节点间 Gossip 消息大小和维护成本。16384 是性能、灵活度、内存开销的最佳平衡点。

2、Key 如何映射到槽?

使用 CRC16 算法计算 Key 的校验值,再对 16384 取模。

3、哈希标签 {} 的作用?

使多个 key 映射到同一个槽,保证 MGET/MSET/Lua 等操作的原子性。

4、扩容时槽位怎么迁移?

通过 CLUSTER SETSLOT 设置槽状态为导入/导出,再用 MIGRATE 迁移数据,整个过程不会中断服务。

5、MOVED 和 ASK 的区别?

MOVED:表示槽永久迁移,客户端需要更新路由

ASK:临时迁移,客户端无需更新路由

6、Redis 为什么不直接采用“一致性哈希”?

因为槽机制更简单、路由更快、迁移粒度更细、有更好的稳定性。

7、一个节点能否管理非连续槽位?

可以。比如:Node A:0-100, 300-500, 800-900

8、槽位迁移时客户端如何知道?

通过 MOVED / ASK 重定向消息。

最后,用一句最容易记住的话总结哈希槽

我拍了拍朋友说:

“Redis Cluster 的哈希槽,就是 16384 个小房间,Key 用 CRC16 算法算出自己住哪间房;房间归节点管理,节点扩容时迁移房间,住户不会丢。”

朋友听完后突然眼睛一亮:

“我懂了!Redis 哈希槽不就是用来均衡数据、提高路由效率、简化扩容、保证多 key 操作落在一起的核心机制吗?”

我笑着说:

“对,就是这么一回事。你已经比 90% 的面试者懂更多了。”

END

如果你正在准备 Java 或后端社招,一定要理解 Redis Cluster 的工作原理。

哈希槽看似是一个名词,本质却是整个 Redis Cluster 世界观的地基。

理解之后,你会发现 Redis 的扩容、缩容、路由、负载均衡、宕机恢复等机制,都变得清晰了。

好朋友们,我们下期再见~