Redis分片集群散列插槽
一、前言为什么 Redis Cluster 用 16384 个槽在 Redis 分片集群Cluster中数据不是随机分布而是通过“散列插槽”Hash Slot机制进行分片。你可能好奇为什么是16384个槽不是 65536 或 1024key 是如何映射到具体节点的为什么MGET user:1 user:2有时会报错本文将带你彻底搞懂 Redis 散列插槽的设计哲学与工作原理。二、散列插槽Redis Cluster 的分片基石2.1 基本概念Redis Cluster 将整个 key 空间划分为16384 个哈希槽slot每个 key 通过公式计算归属哪个 slotslot CRC16(key) % 16384每个 master 节点负责一部分连续或不连续的 slot✅优势分片规则简单、确定扩容/缩容只需迁移 slot无需 rehash 全量数据三、为什么是 16384不是更多或更少这是 Redis 作者Salvatore Sanfilippoantirez在 GitHub issue 中亲自解释的经典问题。3.1 官方理由精简版“16384 is the right balance between:消息大小每个节点每秒通过 gossip 协议广播 cluster state集群规模最多支持 1000 个节点实际建议 ≤ 100内存开销每个 slot 状态需 2 字节16384 × 2 32KB”3.2 详细分析槽位数每节点心跳包大小支持最大节点数内存开销65536~130KB 100128KB16384~32KB~100032KB4096~8KB 10008KB65536 太大心跳包过大网络带宽浪费4096 太小节点多时slot 分配不均如 100 节点平均仅 40 个 slot/节点16384 刚好兼顾扩展性与效率结论16384 是工程上的最优折中。四、Key 到 Slot 的计算过程含代码4.1 CRC16 算法Redis 使用CRC16_CCITT变种初始值 0无反转。4.2 Java 实现示例public class RedisSlot { private static final int SLOT_COUNT 16384; public static int getSlot(String key) { // 1. 提取 Hash Tag如有 String tagKey extractTag(key); // 2. 计算 CRC16 int crc crc16(tagKey.getBytes(StandardCharsets.UTF_8)); // 3. 取模 return crc % SLOT_COUNT; } // 支持 Hash Tag{user1001}.name 和 {user1001}.age 落在同一 slot private static String extractTag(String key) { int start key.indexOf({); if (start ! -1) { int end key.indexOf(}, start 1); if (end ! -1 end ! start 1) { return key.substring(start 1, end); } } return key; } // 简化版 CRC16实际应使用标准实现 private static int crc16(byte[] bytes) { int crc 0; for (byte b : bytes) { crc ((crc 8) ^ LOOKUP_TABLE[((crc 8) ^ (b 0xFF)) 0xFF]) 0xFFFF; } return crc; } private static final int[] LOOKUP_TABLE { /* CRC16 表 */ }; }✅关键点Hash Tag可强制多个 key 落在同一 slot五、客户端如何定位 Key 所在节点当客户端访问一个 key 时流程如下5.1 首次访问无本地缓存随机连接一个节点如 7001节点计算 key 的 slot发现不在自己负责范围返回MOVED 重定向MOVED 5461 192.168.1.10:7002客户端缓存slot - node映射并重连 70025.2 后续访问有缓存直接根据 slot 路由到目标节点无重定向Lettuce / Jedis Cluster 客户端会自动处理 MOVED/ASK六、跨 Slot 操作为何失败6.1 问题场景# 假设 user:1 → slot 1000, user:2 → slot 2000 redis-cli -c MGET user:1 user:2 # 报错CROSSSLOT Keys in request dont hash to the same slot6.2 原因Redis Cluster要求多 key 操作必须在同一 slot否则无法保证原子性和一致性6.3 解决方案使用 Hash Tag# 强制 user:1 和 user:2 落在同一 slot MGET {user100}.name {user100}.age # OK{}内的内容作为 hash keyuser100相同 → slot 相同✅最佳实践对需要 multi-key 操作的数据使用相同 Hash Tag七、Slot 迁移与集群扩容当新增 master 节点时需迁移部分 slot7.1 迁移流程目标节点声明“我将接管 slot X”源节点进入MIGRATING状态客户端访问 slot X 的 key若 key 存在 → 返回ASK 重定向到目标节点若 key 不存在 → 允许在目标节点写入源节点逐步迁移 keyCLUSTER GETKEYSINSLOTMIGRATE迁移完成更新集群拓扑7.2 客户端感知收到ASK时先发 ASKING 命令再发原命令Lettuce/Jedis 自动处理业务无感八、监控与运维命令8.1 查看 slot 分配redis-cli -p 7001 CLUSTER SLOTS # 返回[[0,5460,192.168.1.10,7001], [5461,10922,192.168.1.10,7002], ...]8.2 查看 key 所属 slotredis-cli -p 7001 CLUSTER KEYSLOT user:1001 # 返回54618.3 查看节点负责的 slotsredis-cli -p 7001 CLUSTER NODES # 输出中connected 0-5460九、结语感谢您的阅读如果你有任何疑问或想要分享的经验请在评论区留言交流
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2413157.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!