高级篇 14. 分布式缓存 - 散列插槽 (Hash Slot) 原理剖析

0 阅读5分钟

太棒了!上一节我们成功在 Docker 中拉起了 6 个节点的分片集群,并且一键分配了主从关系和哈希槽。

如果你在面试中说你懂分片集群,面试官的下一个问题 100% 会是: “请详细说一下 Redis 的散列插槽(Hash Slot)机制,以及它是如何解决数据倾斜和事务路由问题的?”


📚 高级篇 14. 分布式缓存 - 散列插槽 (Hash Slot) 原理剖析

一、 核心认知:放弃一致性哈希,拥抱哈希槽

在早期的分布式架构中,将数据打散到多台机器通常会使用“一致性哈希算法”。但 Redis 官方在设计 Cluster 时并没有采用它,而是创造性地引入了 散列插槽 (Hash Slot)

🌟 什么是散列插槽?

Redis Cluster 在逻辑上把整个集群的数据存储空间划分成了 16384 个固定大小的槽位(编号为 0 ~ 16383)。

在集群建立之初,这些槽位会被均匀地分配给所有的 Master 节点。

假设我们有 3 台 Master:

  • Master A 负责槽位:0 ~ 5460
  • Master B 负责槽位:5461 ~ 10922
  • Master C 负责槽位:10923 ~ 16383

数据永远是和“插槽”绑定的,而不是和“具体的物理机器”绑定的。 这种设计的最大好处就是扩容和缩容极其方便(只需要把插槽从一台机器迁移到另一台机器,数据就会跟着平滑迁移)。


二、 数据路由机制:一条 Key 是如何找到家的?

当 Java 客户端发来一条写命令(例如:set num 123),Redis 集群是如何决定把它存到哪台 Master 上的?

Redis 会对这条数据的 Key 进行一系列的数学运算,最终得出它归属的槽位。核心路由公式如下:

hash_slot=CRC16(key)(mod16384)hash\_slot = \text{CRC16}(key) \pmod{16384}

运算步骤拆解:

  1. CRC16 算法: 首先,Redis 使用 CRC16 算法对 key(比如 "num")进行哈希计算,得出一个 16 位的整数。
  2. 取模运算: 将这个算出来的整数对 16384 进行取模(求余数)。
  3. 精准定位: 最终得到的余数一定在 0 ~ 16383 之间。这个数字就是该数据的槽位号。Redis 去查一下内部的映射表,看看这个槽位归哪台 Master 管,就把数据存到哪里。

三、 大厂高频拷问:Hash Tag 与跨节点事务灾难

理解了基本路由规则后,面试官通常会立刻抛出一个极其致命的生产级问题。

🗣️ 面试官发难: “在秒杀系统中,我们经常需要用 Lua 脚本来保证多个命令的原子性(比如同时扣减库存和生成订单)。但是,如果‘库存 Key’和‘订单 Key’算出来的哈希槽不在同一台 Master 上,Redis 集群会直接报错拒绝执行!请问你该如何解决这个跨节点操作的灾难?”

💡 你的满分破局方案:使用 Hash Tag (大括号法则)

“Redis 在计算哈希槽时,有一个非常精妙的后门规则——有效部分(Hash Tag)

默认情况下,Redis 会使用整个 Key 来计算散列值。但是,如果 Key 中包含了大括号 {},Redis 就只会对大括号里面的内容进行哈希计算!

利用这个特性,我们可以人为地干预数据的路由分布。

例如,我把库存的 Key 设计为 seckill:{1001}:stock,把订单的 Key 设计为 seckill:{1001}:order

只要在执行操作时,Redis 发现它们都有 {1001},它就只会拿 1001 去做 CRC16 计算。这样算出来的槽位号绝对是一模一样的!我们就强行把这两个相关的 Key 路由到了同一个哈希槽(同一台 Master)上,完美解决了集群模式下的 Lua 脚本事务执行问题。”


四、 客户端重定向:MOVED 报错与智能路由

在分片集群中,由于没有了中心代理,如果你用普通的命令行客户端(redis-cli)随便连上一台节点(比如连了 Master A),然后执行 set name jack

如果经过公式计算,name 这个 Key 的槽位归 Master B 管,Master A 会怎么做?它会帮你把数据转发过去吗?

不会!Redis 节点非常懒,它绝不代劳!

  1. MOVED 拒绝: Master A 会直接给你抛出一个报错:(error) MOVED 5798 192.168.1.102:8002
  2. 报错含义: 意思是“别找我,这个 Key 算出来的槽位是 5798,你去 192.168.1.102:8002(Master B 的地址)找它!”
  3. 集群模式启动: 为了让命令行客户端能自动跳转,我们在连接时必须加上 -c 参数(redis-cli -c -p 8001)。加上 -c 后,客户端遇到 MOVED 报错,就会自动隐式地帮你重定向连到 Master B 去执行命令。

学习总结

这节课你掌握了 Redis 分片集群最底层的路由灵魂——散列插槽机制

你需要牢记路由公式 hash_slot=CRC16(key)(mod16384)hash\_slot = \text{CRC16}(key) \pmod{16384},并且深刻理解 Hash Tag ({}) 的妙用。在真实的企业级高并发开发中,利用 Hash Tag 将同一类业务数据强制绑定到同一个槽位,是避免跨节点网络开销和事务报错的标准化操作。