Redis 分片集群与哈希槽笔记 一、什么是 Redis 分片集群Redis 分片集群通常指 Redis Cluster。它的主要作用是将数据分散到多个 Redis 主节点上。突破单台 Redis 的内存容量限制。提高整个集群的读写能力。配合主从复制实现高可用。典型结构master A master B master C | | | replica A replica B replica C其中多个 master 保存不同的数据负责数据分片。replica 复制对应 master 的数据负责故障恢复。因此Redis Cluster 数据分片 主从复制 故障转移二、什么是哈希槽Redis Cluster 将整个数据空间划分为16384 个哈希槽槽编号范围0 16383槽不是实际的内存块也不会提前占用固定大小的内存。槽本质上只是一个逻辑编号用来对 key 进行分组和路由。例如槽 100可能没有 key 槽 200可能有 1 个 key 槽 300可能有 10000 个 key因此槽的数据量并不固定。三、key 如何确定所属槽Redis 会根据 key 计算槽号slot CRC16(key) % 16384例如user:1 → 槽 3000 shop:1 → 槽 7000 order:1 → 槽 13000只要 key 的内容不变按照同样的计算规则它对应的槽号就不会改变。完整关系key ↓ 计算 槽号 ↓ 查询归属 Redis master 节点例如user:1 ↓ 槽 3000 ↓ master A所以数据不是直接根据 key 分配给节点而是经过一层槽key → 槽 → 节点四、槽和数据的关系槽是对数据的逻辑分组不是实际保存数据的地方。真正的数据仍然保存在 Redis 节点自己的内存中。例如槽 05000 → master A 槽 500110000 → master B 槽 1000116383 → master C如果user:1 → 槽 3000那么user:1就实际保存在 master A 的内存中。可以理解为槽属于哪个 master ↓ 该槽中的 key 就存在哪个 master五、为什么需要槽如果不使用槽而直接按照节点数量计算节点 hash(key) % 节点数量原来有 3 个节点hash(key) % 3扩容为 4 个节点后hash(key) % 4因为取模数字发生变化大量 key 的计算结果都会改变因此可能需要迁移大量数据。使用固定的 16384 个槽后key → 槽这个映射基本不变。扩容或缩容时只需要修改槽 → 节点然后迁移这些槽中的数据。因此槽的核心作用是将 key 的分布规则与 Redis 节点数量分离。六、扩容时槽如何迁移假设原来槽 5000 → master A槽 5000 中的数据也都存放在 master A。现在增加 master B并准备将槽 5000 交给 B。不能只修改槽的归属而不迁移数据。正确过程是1. 将槽 5000 标记为正在从 A 迁移到 B 2. 将槽 5000 中的 key 从 A 逐个迁移到 B 3. 数据迁移完成 4. 正式将槽 5000 的归属修改为 B最终结果迁移前 槽 5000 → master A 数据 → master A 迁移后 槽 5000 → master B 数据 → master B所以扩容时真正需要处理两件事修改槽归属 迁移槽中的实际数据七、迁移过程中数据在哪里迁移槽不是直接搬运一整块内存而是逐个迁移槽中的 key。例如槽 5000 中有key1 key2 key3迁移过程中可能出现key1 已经迁移到 B key2 仍然留在 A key3 仍然留在 A因此迁移过程中数据可能暂时同时分布在 A 和 B。Redis 会通过迁移状态和ASK重定向保证请求能够找到正确的数据。迁移完成后槽 5000 中的所有 key 都在 B 槽 5000 正式归 B 管理正常情况下不会长期存在槽归 B 管理 数据却一直留在 A因为 Redis 节点只能直接管理自己进程内存中的数据B 不能直接管理 A 内存中的 key。八、ASK 和 MOVED1. ASK槽正在迁移时如果客户端访问了已经被迁移到新节点的 key旧节点会返回ASK 槽号 新节点地址含义该槽还在迁移这一次请求暂时去新节点执行。ASK是临时重定向。2. MOVED槽已经正式归新节点管理后客户端访问旧节点会收到MOVED 槽号 新节点地址含义该槽已经正式属于新节点以后都应该访问新节点。MOVED是正式重定向。九、不同 key 存在不同服务器怎么办这是分片集群的正常情况。例如user:1 → master A shop:1 → master B order:1 → master C客户端会1. 根据 key 计算槽号 2. 查询该槽由哪个节点负责 3. 将请求发送给正确节点通常由 Lettuce、Jedis、Redisson 等集群客户端自动完成。因此单 key 操作一般没有问题GET user:1 SET shop:1 value HGET order:1 status客户端会自动将不同请求发送给不同节点。十、多 key 操作的问题如果一条命令同时操作多个 key而这些 key 属于不同槽就可能报错CROSSSLOT Keys in request dont hash to the same slot例如MGET user:1 shop:1假设user:1 → master A shop:1 → master B一条 Redis 命令无法同时在两个节点上原子执行。受影响的操作包括MGET MSET DEL 多个 key 事务 Lua 脚本 集合交集、并集、差集十一、Hash Tag为了让相关 key 进入同一个槽可以使用{}。例如user:{1}:name user:{1}:age user:{1}:ordersRedis 计算槽位时只计算大括号中的内容1因此这些 key 一定属于同一个槽也会存放在同一个 master 节点上。例如seckill:{10}:stock seckill:{10}:order这两个 key 都使用{10}计算槽号因此可以在同一个 Lua 脚本中操作。但是user:{1}:name user:{2}:name大括号内容不同仍然可能进入不同槽。十二、核心理解Redis Cluster 中有两层映射第一层key → 槽 第二层槽 → master 节点其中key → 槽由固定的哈希规则决定只要 key 不变槽号通常就不变。而槽 → 节点可以随着扩容、缩容、故障转移而改变。当槽的归属改变时必须将槽中的实际数据迁移到新的节点。最终可以记住这句话key 决定自己属于哪个槽集群决定槽属于哪个 master槽归属发生变化时槽中的数据也必须迁移到新的 master。