分片策略详解:范围分片、哈希分片与一致性哈希
为什么要选分片策略
分片策略决定了数据如何分布到不同的数据库或表中。不同的策略在数据分布均匀性、可扩展性和查询效率上有不同的表现。
一、范围分片(Range Sharding)
原理
按分片键的取值范围划分数据:
// 按 user_id 范围分片
user_id 1-1000万 → 表 0
user_id 1000万-2000万 → 表 1
user_id 2000万-3000万 → 表 2
...
实现方式
-- 以 user_id 按范围分表
-- 应用层或中间件根据值判断走哪张表
String getTableName(long userId) {
if (userId <= 10_000_000) return "user_0";
if (userId <= 20_000_000) return "user_1";
if (userId <= 30_000_000) return "user_2";
return "user_3";
}
优点
- 实现简单,路由逻辑直观
- 范围查询效率高:
WHERE id BETWEEN 100 AND 200大概率落在同一分片 - 扩容方便:数据量到上限时,新增分片,将新数据写入新分片即可
缺点
- 数据分布可能不均衡:某些范围的数据量远大于其他范围
- 热点问题:按时间分片时,新数据的写入集中在最后的分片
二、哈希分片(Hash Sharding)
原理
对分片键计算哈希值,再对分片数取模:
int shardId = hash(shardKey) % shardCount;
实现方式
// 基于 user_id 哈希分片
int shardId = user_id % 4; // 4 个分片
String dbName = "order_db_" + shardId;
// 或者更好的哈希函数
int shardId = Math.abs(user_id.hashCode()) % shardCount;
优点
- 数据分布均匀:哈希值的随机性保证了各分片数据量大致相等
- 避免热点:写入请求均匀分散到各分片
- 查询效率稳定:无论哪个分片,单表数据量相当
缺点
- 范围查询困难:相邻 ID 的数据分散在不同分片,需要查询所有分片后合并
- 扩缩容困难:分片数变化后,取模基数改变,大量数据需要迁移
三、一致性哈希(Consistent Hash)
原理
一致性哈希将分片键的哈希值映射到一个虚拟环上,数据按顺时针方向存储到最近的分片节点。
NodeA
┌───────────┐
╱ ╲
NodeD NodeB
╲ ╱
└───────────┘
NodeC
解决扩容问题的关键
传统取模分片扩容时,$新分片数 \neq 旧分片数$,导致几乎所有数据都需要重新分布。一致性哈希加入一个分片时,只需要迁移邻近分片的数据。
加入 NodeE 前:
hash(user_1) → NodeA
hash(user_2) → NodeB
hash(user_3) → NodeC
加入 NodeE 后(在 NodeA 和 NodeB 之间):
hash(user_1) → NodeA (不变)
hash(user_2) → NodeE (从 NodeB 迁移到 NodeE)
hash(user_3) → NodeC (不变)
虚拟节点
为了解决物理节点在环上分布不均匀(数据倾斜)的问题,一致性哈希引入虚拟节点——每个物理节点在环上对应多个虚拟节点:
物理节点:NodeA, NodeB, NodeC
虚拟节点:A1, A2, A3, B1, B2, B3, C1, C2, C3
每个物理节点对应多个虚拟节点,均匀分布在哈希环上,数据分布更均衡。当某个物理节点下线时,它的虚拟节点分散到其他节点,负载平摊。
三种策略对比
| 维度 | 范围分片 | 哈希分片 | 一致性哈希 |
|---|---|---|---|
| 数据均匀性 | 可能倾斜 | 均匀 | 均匀(虚拟节点加持) |
| 范围查询 | ✅ 高效 | ❌ 需要广播 | ❌ 需要广播 |
| 扩缩容 | ✅ 方便 | ❌ 需要迁移 | ✅ 少量迁移 |
| 实现复杂度 | 简单 | 简单 | 较高 |
| 热点问题 | 有 | 无 | 无 |
| 跨分片合并 | 较少 | 较多 | 较多 |
实际应用中的混合策略
很多分库分表中间件支持混合策略:
策略:先用 hash 分库,再用 range 分表
db = hash(user_id) % db_count
table = (user_id / range_size) % table_count_per_db
策略:时间维度 + 用户维度
db = hash(user_id) % db_count -- 用户维度
table = date_to_month_range(date) -- 时间维度
面试要点
- 理解每种策略的核心原理和适用场景
- 重点对比:范围分片适合范围查询、哈希分片适合写入均匀、一致性哈希适合动态扩缩容
- 一致性哈希的虚拟节点为什么能解决数据倾斜
- 在面试中能根据业务场景推荐分片策略并说明理由
- 扩缩容是分片策略选择中最重要的考量因素之一
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END


暂无评论内容