大家好,我是 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% 的面试者懂更多了。”

如果你正在准备 Java 或后端社招,一定要理解 Redis Cluster 的工作原理。
哈希槽看似是一个名词,本质却是整个 Redis Cluster 世界观的地基。
理解之后,你会发现 Redis 的扩容、缩容、路由、负载均衡、宕机恢复等机制,都变得清晰了。
好朋友们,我们下期再见~