redis集群分片策略
核心概念:哈希槽(Hash Slot)
Redis 集群的分片策略并非基于一致性哈希,而是引入了一个名为 哈希槽(Hash Slot) 的核心概念。这是理解整个机制的关键。
固定数量的槽:Redis 集群将整个数据集划分为 16384(2^14)个哈希槽。
数据映射到槽:每个写入的键(Key)都会通过一个 CRC16 算法计算出一个哈希值,然后将这个哈希值对 16384 取模,得到的结果(0 到 16383 之间的一个数)就是这个键所属的哈希槽。
slot = CRC16(key) % 16384
槽分配给节点:集群中的每个主节点(Master)负责处理一部分哈希槽。槽的分配信息(即哪个节点负责哪些槽)存储在每个节点中,并且会在集群中自动传播(使用 Gossip 协议),因此每个客户端都可以连接到任意节点并获取到最新的集群配置。
分片策略的工作原理
1. 键到槽的映射
当你执行 SET mykey myvalue
时,集群会:
计算
mykey
的哈希槽:CRC16("mykey") % 16384
。根据本地的集群配置信息,判断这个槽由哪个节点负责。
如果该槽正好由当前连接的节点负责,则直接执行命令。
如果该槽由另一个节点负责,当前节点会向客户端返回一个 MOVED 错误重定向,并告知正确的节点地址。智能的 Redis 客户端(如
redis-cli -c
)会自动根据这个重定向信息,将命令转发到正确的节点执行。
2. 哈希标签(Hash Tags)
默认的分片方式可能会导致那些本应存储在同一节点上的相关键(例如 user:1000:profile
和 user:1000:orders
)被分散到不同的节点上,因为它们的键名不同。
为了解决这个问题,Redis 集群引入了 哈希标签(Hash Tags)。你可以使用 {}
来指定只计算括号内部分字符串的哈希值。
没有哈希标签:
user:1000:profile
-> 计算user:1000:profile
的 CRC16user:1000:orders
-> 计算user:1000:orders
的 CRC16这两个键很可能被分配到不同的槽。
使用哈希标签:
user:{1000}:profile
-> 计算1000
的 CRC16user:{1000}:orders
-> 计算1000
的 CRC16这两个键会被分配到同一个槽,从而保证存储在同一个节点上。这对于执行多键操作(如事务、Lua脚本)至关重要。
集群管理:重分片(Resharding)
Redis 集群最强大的特性之一就是在线重分片能力。你可以在集群正常运行、不停机的情况下,增加或移除节点,并重新分配哈希槽。
重分片过程:
发起:使用
redis-cli --cluster reshard
命令工具发起重分片操作。规划:指定要从哪些源节点迁移槽,迁移到哪个目标节点,以及迁移多少槽。
迁移:迁移过程是以槽为单位的。对于槽中的每个键:
工具会向源节点和目标节点发送准备命令。
源节点将指定键的数据序列化并发送给目标节点。
目标节点接收并反序列化数据后,存储到本地。
迁移完成后,工具会向源节点和目的节点发送确认命令。
更新配置:将迁移的槽的所有权从源节点正式分配给目标节点。这个新的槽分配信息会通过 Gossip 协议传播到整个集群。
在迁移过程中,如果客户端访问一个已经被迁移走的键,源节点会先检查该键是否还存在本地。如果不存在,它会返回一个 ASK 重定向错误(与 MOVED 不同),引导客户端去目标节点临时获取数据。一旦迁移完成,所有请求都会通过 MOVED 重定向到新的目标节点。
与其他分片方案的对比
特性 | Redis 原生集群 (哈希槽) | 客户端分片 (如 ShardedJedis) | 代理分片 (如 Twemproxy, Codis) |
---|---|---|---|
架构 | 去中心化(P2P),每个节点平等 | 在客户端库中实现逻辑 | 中心化代理,客户端连接代理 |
可扩展性 | 高,支持在线平滑扩缩容 | 低,扩缩容需停机、手动数据迁移 | 中,扩缩容比客户端分片方便,但仍有开销 |
性能 | 高,无代理层,直接通信 | 高,无代理开销 | 中,多一层网络跳转,有性能损耗 |
配置管理 | 自动 gossip 传播,客户端需支持重定向 | 配置在客户端,难以维护 | 代理层统一管理,客户端无感知 |
功能支持 | 不支持多键操作(除非在同槽) | 依赖客户端实现 | 代理层可能屏蔽一些高级命令 |
复杂度 | 中等,需理解集群概念和运维工具 | 低(简单应用),高(运维复杂) | 低(对客户端),高(维护代理层) |
总结
Redis 集群采用基于 哈希槽 的分片策略,其核心优势在于:
易于管理和扩展:16384 个固定槽简化了数据分布和节点管理。
在线重分片:支持不停机地增加或移除节点,是实现高可用的基础。
高性能:去中心化的设计避免了代理层的开销。
灵活性:通过哈希标签可以控制相关键的分布,以支持必要的事务操作。
这种设计使得 Redis 集群成为一个成熟、稳定、高性能的分布式内存数据库解决方案。