Redis Cluster 核心原理:哈希槽与数据路由实战

在 Redis 的高可用架构中,分片集群(Sharding Cluster)解决了单机内存和性能瓶颈。不同于主从哨兵模式,分片集群引入了"哈希槽"的概念,实现了数据的去中心化存储。

今天,我们就来彻底搞懂 Redis 集群是如何通过哈希槽来分配数据,以及如何利用这一机制优化我们的业务存储。

哈希槽:集群的"物流分拣系统"

Redis 集群并没有采用一致性哈希,而是引入了哈希槽的概念。这是一个非常精妙的设计,我们可以把它想象成一个拥有 16384 个格口的物流分拣中心。(有同学可能要问为什么是16384,我特意去搜了下,这是个最佳实践,大小4kb)

总量固定:Redis 集群预定义了 16384 个哈希槽,编号从 0 到 16383。

  • 节点映射 :集群中的每个 Master 节点会负责一部分槽位。例如,一个 3 主 3 从的集群,槽位分配可能如下:
    • 节点 7001:负责 0 - 5460
    • 节点 7002:负责 5461 - 10922
    • 节点 7003:负责 10923 - 16383

数据并不是直接绑定在某个节点上,而是绑定在槽位上。这种设计让集群的扩容和缩容变得异常简单------只需要移动槽位即可,无需全量迁移数据。

数据路由:你的数据去哪了?

当我们执行 SET key value 时,Redis 是如何知道该把数据存在哪台机器上的呢?这依赖于一个三步走的计算流程。

第一步:确定"有效部分"

Redis 首先会检查 Key 中是否包含大括号 {}

  • 无大括号 :整个 Key 就是有效部分。例如 num 的有效部分就是 num
  • 有大括号 :只有大括号 {} 内部的内容才是有效部分。例如 {itcast}num 的有效部分是 itcast

第二步:计算哈希值

利用 CRC16 算法对"有效部分"进行计算,得到一个哈希值。

第三步:取模定位

将哈希值对 16384 取余,得到的余数就是该 Key 所属的槽位编号。

计算公式

SLOT=CRC16(key) & 16383

实战演练:控制数据存储位置

理解了原理,我们来看看在实际操作中会发生什么。假设我们连接到了 7001 节点(使用 redis-cli -c -p 7001,注意 -c 参数开启了智能路由,这个一定不要省略)。

场景一:普通存储

当我们执行 SET num 123 时:

  1. 有效部分是 num
  2. 计算 CRC16("num") % 16384,结果为 2765。
  3. 2765 在 0-5460 范围内,属于 7001 节点。
  4. 结果:数据直接存储在 7001。

场景二:触发重定向

当我们执行 SET a 1 时:

  1. 有效部分是 a
  2. 计算 CRC16("a") % 16384,结果为 15495。
  3. 15495 在 10923-16383 范围内,属于 7003 节点。
  4. 结果:7001 节点发现该槽位不归自己管,会返回一个 MOVED 错误,告诉客户端:"去 7003 节点找"。客户端收到后会自动跳转。

场景三:利用哈希标签

如果我们执行 SET {a}number 1

  1. 有效部分变成了 {} 中的 a
  2. 计算结果依然是 15495(因为有效部分还是 a)。
  3. 结果:数据被路由到 7003 节点。
进阶技巧:哈希标签的商业价值

你可能会问,为什么要设计 {} 这种机制?难道就是为了把数据存到别的节点吗?当然不是。哈希标签是解决"跨槽操作"难题的钥匙。

在 Redis 集群中,涉及多个 Key 的操作(如 MGETMSET 或 事务)要求所有 Key 必须在同一个槽位上,否则会报错。

应用场景:商品分类存储

假设我们要存储用户 1001 的姓名、年龄和城市。为了保证事务的一致性,我们需要它们存储在同一个节点上。

  • SET {user:1001}:name "Alice"
  • SET {user:1001}:age 25
  • SET {user:1001}:city "Beijing"

通过将 {user:1001} 作为哈希标签,Redis 在计算槽位时,只会计算 user:1001 的哈希值。因此,这三个 Key 会落入同一个槽位,也就必然在同一个节点上。

知识小结:核心考点速查表

为了方便大家复习,我将本文的重点整理成了下表:

知识点 核心内容 技术实现 应用场景
哈希槽 16384 个槽位分配到集群节点 CRC16 算法计算 key 的哈希值并取模 数据存储位置判定、数据分片
插槽分配 7001: 0-5460 7002: 5461-10922 7003: 10923-16383 集群初始化时自动分配 实现数据分片存储
Key 路由机制 根据有效部分计算插槽值 1. 带 {} 时取括号内内容 2. 无 {} 时取整个 key SET number 123 → 2765 插槽 SET {a}number 1 → 15495 插槽 自动重定向到正确节点
数据绑定原理 数据与插槽绑定而非节点 节点故障时插槽转移 保证数据可定位性
哈希标签 控制 key 的有效部分 SET {mobile}1001 SET {mobile}1002 商品分类存储、批量查询优化
操作命令演示 插槽计算 → 重定向节点 → 现象说明 SET number 123 (7001) SET a 1 (7003, MOVED) SET {a}number 1 (7003) 验证有效部分变为大括号内容

总结

  • 集群通过 16384 个槽位实现数据分片。
  • 数据路由依赖于 CRC16 算法和 % 16384 取模。
  • 利用 {} 哈希标签,我们可以强制将相关联的数据"捆绑"在同一个节点,从而支持批量操作和事务,这是生产环境优化的关键技巧。
相关推荐
周末也要写八哥2 小时前
追求性能极致为何不用Redis?
数据库·redis·缓存
JosieBook2 小时前
【Redis】Redis如何修改密码?
数据库·redis·bootstrap
wfbcg2 小时前
每日算法练习:LeetCode 15. 三数之和 ✅
算法·leetcode·职场和发展
2301_822703202 小时前
开源鸿蒙跨平台Flutter开发:跨端图形渲染引擎的类型边界与命名空间陷阱:以多维雷达图绘制中的 dart:ui 及 StrokeJoin 异常为例
算法·flutter·ui·开源·图形渲染·harmonyos·鸿蒙
y = xⁿ2 小时前
【LeetCode Hot100】双指针:分离指针
算法·leetcode
学习永无止境@2 小时前
Verilog中有符号数计算
图像处理·算法·fpga开发
6Hzlia2 小时前
【Hot 100 刷题计划】 LeetCode 41. 缺失的第一个正数 | C++ 原地哈希题解
c++·leetcode·哈希算法
一个有温度的技术博主2 小时前
Redis集群实战:如何实现节点的弹性伸缩与数据迁移?
redis·分布式·缓存·架构
小肝一下2 小时前
每日两道力扣,day6
数据结构·c++·算法·leetcode·双指针·hot100