分片键就是决定分布在不同节点上的字段或字段组合
哈希分片
哈希分片的核心思想是(先获取分片键对应的哈希函数,再获取分片编号):
- 对数据的某个关键字段(称为分片键/Shard Key)应用哈希函数
- 根据哈希结果决定数据应该存储在哪个分片上
数学表达式为:
分片编号 = hash(分片键) % 分片总数
范围分片
范围分片的核心思想是(直接根据分片键划分区间,无需哈希计算):
- 按照分片键(Shard Key)的值范围将数据划分为连续区间
- 每个区间分配给特定的分片(节点)
- 相邻的数据通常会被分配到同一个分片
数学表达式为:
分片编号 = find_first_range_containing(shard_key)
2. 范围分片实现方式
一致性哈希
当节点数量变化时,需要进行大规模的数据转移,一致性哈希就是解决分布式系统中节点动态变化导致的数据大规模迁移问题,与传统的哈希分片有所区别 ,在数据量 激增的时候,需要增加节点的时候 ,大幅减少数据迁移量
实现的具体步骤: 大致构建一个首位相连的环, 每个节点和数据都有相应的哈希值,而数据顺时针寻找属于自己最近的节点,节点和数据的哈希值都通过特定的哈希函数获得
1. 构建哈希环
- 使用一个足够大的哈希空间(通常为
0 ~ 2³²-1
),首尾相连成环。 - 节点哈希:对每个节点的唯一标识(如IP+端口)计算哈希值,映射到环上。
python
复制
# 示例:计算节点哈希值
def hash_node(node):
return crc32(node.ip + ":" + str(node.port)) % 2**32
- 数据哈希:对数据的键(Key)计算哈希值,同样映射到环上。
python
复制
# 示例:计算数据哈希值
def hash_key(key):
return crc32(key.encode()) % 2**32
2. 数据存储逻辑
- 数据存储时,从自己的哈希位置顺时针方向找到第一个节点作为归属节点。
python
复制
# 伪代码:查找数据所属节点
def find_node(key, sorted_node_hashes):
key_hash = hash_key(key)
# 二分查找第一个 >= key_hash 的节点
for node_hash in sorted_node_hashes:
if node_hash >= key_hash:
return node_hash
# 环回处理:返回第一个节点
return sorted_node_hashes[0]
3. 节点动态变化时的处理
- 新增节点:
-
- 计算新节点的哈希值,插入环中。
- 仅需迁移新节点与逆时针相邻节点之间的数据。
python
复制
# 伪代码:新增节点S4(假设哈希值为5000)
new_node_hash = 5000
# 受影响的数据范围:前驱节点S2(3000) → S4(5000)
migrate_data = [data for data in all_data if 3000 < hash_key(data.key) <= 5000]
移除节点:
将该节点的数据全部转移到顺时针方向的下一个节点。
4. 虚拟节点(Virtual Nodes)优化
问题:直接哈希可能导致数据分布不均(某些节点负载过高)。
解决:为每个物理节点分配多个虚拟节点(如100个),均匀分布在环上。
python
复制
# 示例:为物理节点S1分配100个虚拟节点
for i in range(100):
virtual_node_hash = crc32(f"S1-virtual-{i}") % 2**32
ring.add(virtual_node_hash, physical_node=S1)
优势:
数据分布更均匀
支持节点权重(高性能节点可分配更多虚拟节点)
🎯 关键点总结
概念 | 说明 |
哈希环 | 逻辑上的环形结构(0~2³²-1),节点和数据通过哈希函数映射到环上。 |
顺时针查找 | 数据归属的判定规则,确保确定性。 |
虚拟节点 | 解决数据倾斜问题,提高负载均衡性。 |
动态扩展 | 增删节点时仅影响相邻数据,迁移量从O(N)降到O(1/N)。 |
时间复杂度 | 查找节点:O(logN)(用二分查找维护有序节点列表)。 |
🌰 完整示例流程
假设有一个哈希环,初始有3个节点(S1, S2, S3)和3条数据:
节点哈希值:
S1 → 1000
S2 → 3000
S3 → 6000
数据哈希值:
"user:1001" → 1500 → 归属 S2(顺时针第一个≥1500的节点)
"user:1002" → 4000 → 归属 S3
"user:1003" → 6500 → 环回归属 S1
新增节点S4(哈希值5000):
受影响数据范围:3000 < hash ≤ 5000 → 仅 "user:1002" 从S3迁移到S4。
💡 为什么这种方法高效?
数据迁移最少化:仅调整局部数据归属,避免全局重新哈希。
负载均衡:虚拟节点让数据均匀分布,避免热点。
扩展性:适合动态变化的分布式环境(如云原生架构)。
一致性哈希的精妙之处在于用环形拓扑+局部调整,完美平衡了扩展性和性能,成为分布式系统的基石算法之一! 🚀
一致性哈希数据迁移规律总结
一致性哈希再迁移数据时只需要迁移一部分数据,因为本来所有的 数据的哈希值和所有的节点的哈希值 都已经是一定的了,即使进行数据迁移,也 照样是按照原本的哈希函数获取的哈希值, 所以原本顺时针具有相邻节点的数据是 不会改变的(相邻节点的哈希值>= 数据的哈希值), 而原来需要回环的数据 (即数据哈希值超过最大节点哈希),这些回环的数据原本都归属于第一个节点, 进行数据 迁移时,这些回环的数据是要进行迁移的数据,但也只是一部分或者 全部 ,只要不落在新节点的接管区间,也无需迁移。