MySQL 分片算法
在理解各种分片算法之前,需要先明确一个核心问题:
分片算法解决的不是“如何存储数据”,而是“给定一条数据,如何决定它应该进入哪个分片”。
例如:
现在有:
用户表 user
user_id | name
----------------
10001 | Tom
10002 | Jack
10003 | Alice
有三个数据库:
db0
db1
db2
系统必须回答:
user_id=10001
应该放:
db0?
db1?
db2?
这个映射关系:
分片键
|
|
分片算法
|
|
目标分片
就是 Sharding Algorithm。
1. 分片算法需要解决什么问题?
一个好的分片算法通常需要考虑几个目标:
2. 数据均匀分布
希望:
db0:
1亿数据
db1:
1亿数据
db2:
1亿数据
而不是:
db0:
2.9亿
db1:
500万
db2:
500万
否则:
一个节点成为热点。
3. 查询能够快速定位
例如:
查询:
select *
from orders
where user_id=10001;
最好:
一次定位:
db1
而不是:
db0查询
db1查询
db2查询
...
4. 扩容成本低
业务增长:
原来:
4个数据库
变成:
8个数据库
希望:
不要迁移大量数据。
所以不同算法,本质是在这些目标之间做权衡。
5. Hash 分片算法
Hash 是最经典的分片算法。
6. 基本思想
使用哈希函数:
分片位置 = hash(分片键) % 分片数量
例如:
4个数据库:
db0
db1
db2
db3
用户:
user_id=10001
计算:
hash(10001)=xxx
假设:
xxx % 4 = 1
那么:
db1
7. 简单取模算法
最简单:
database = user_id % N
例如:
N=4:
10001 % 4
=1
所以:
db1
数据:
user_id=10001
↓
db1
8. 优点
8.1. 数据均衡
因为 hash 会打散数据。
例如:
用户:
1
2
3
4
5
6
经过:
id % 4
得到:
db1
db2
db3
db0
db1
db2
比较平均。
8.2. 查询效率高
因为:
已知:
user_id
直接计算:
目标数据库
不需要扫描。
9. 最大问题:扩容困难
假设:
原来:
4个库:
id % 4
数据:
10001 %4=1
在:
db1
现在扩容:
8个库:
id %8
计算:
10001%8=1
这个刚好没变化。
但是:
例如:
10002
旧:
10002%4=2
新:
10002%8=2
部分相同。
再看:
10003
旧:
3
新:
3
看起来没问题。
但是:
实际上:
当 N 从:
4→8
变化时,大量数据映射会变化。
例如:
旧:
id%4
范围:
0 1 2 3
新:
0 1 2 3 4 5 6 7
大量数据需要重新计算。
如果:
4个节点
100TB数据
扩容:
8节点
可能:
迁移几十TB。
生产无法接受。
10. 一致性哈希(Consistent Hash)
一致性哈希就是为了解决:
普通Hash扩容导致大量数据迁移。
11. 基本思想
普通Hash:
hash(key)%N
依赖:
N
节点数量变化:
映射全部变化。
一致性哈希:
把整个Hash空间变成一个环。
例如:
0
DB0 DB1
DB3 DB2
2^32
节点:
放在环上。
数据:
也计算hash:
例如:
user_id=10001
hash=500
然后:
顺时针找到第一个数据库。
例如:
hash位置500
↓
DB2
数据放:
DB2
12. 增加节点时发生什么?
原来:
DB0
DB1
DB2
DB3
增加:
DB4
只影响:
DB4附近的数据。
例如:
原来:
DB2负责:
500-800
现在:
DB4加入
600-700
只迁移:
600-700
这一部分。
不是全部数据。
13. 虚拟节点问题
简单一致性哈希有问题:
节点分布可能不均。
例如:
DB0
DB1
DB2
可能:
DB0负责:
80%数据。
解决:
虚拟节点。
例如:
真实节点:
DB0
变成:
DB0-1
DB0-2
DB0-3
...
多个虚拟位置。
最终:
Hash环:
DB0-1
DB1-5
DB2-8
DB0-9
...
数据更加均匀。
14. 一致性哈希应用
典型:
15. Redis Cluster
不过 Redis 使用的是:
Slot思想。
16. CDN缓存
例如:
用户请求:
图片
根据hash:
选择缓存节点。
17. 分布式缓存
18. 范围分片(Range Sharding)
范围分片不是计算,而是按照范围划分。
例如:
订单ID:
0-1000万
放:
db0
1000万-2000万
放:
db1
结构:
db0
id:
0-10000000
db1
id:
10000001-20000000
db2
id:
20000001-30000000
19. 优点
20. 范围查询非常快
例如:
查询:
where id between 100 and 200
直接:
db0
不用广播。
21. 数据天然有序
适合:
时间数据。
例如:
日志:
2026-01
db0
2026-02
db1
2026-03
db2
22. 缺点
23. 热点问题
例如:
订单ID:
递增。
最新订单:
全部进入:
db2
结果:
db2:
CPU 100%
db0:
20%
这叫:
写热点
24. 时间分片(Time Based Sharding)
范围分片的一种特殊形式。
例如:
日志系统:
2026-01
db_01
2026-02
db_02
2026-03
db_03
非常适合:
-
日志
-
监控数据
-
时序数据
例如:
Prometheus TSDB:
也是类似思想。
缺点:
冷热不均。
最近月份:
大量写入。
历史月份:
几乎不访问。
25. 目录分片(Directory Based Sharding)
也叫:
查找表分片。
核心思想:
不用算法计算。
维护一个映射表。
例如:
user_mapping
user_id | shard
10001 | db1
10002 | db3
10003 | db2
查询:
先查:
mapping表
得到:
db1
然后访问。
26. 优点
非常灵活。
可以:
人工调整。
例如:
发现:
大客户:
user_id=88888
迁移:
db5
修改:
mapping
即可。
27. 缺点
增加依赖。
如果:
mapping服务挂了:
所有查询失败。
所以通常:
缓存:
Redis
+
本地缓存
28. 组合分片算法(Composite Sharding)
生产中最常见。
因为单一算法经常不够。
例如:
电商订单。
需求:
用户查询快。
同时避免热点。
可以:
第一层:
hash user_id
第二层:
hash order_id
例如:
user_id
|
hash
|
16个数据库
|
order_id hash
|
64张表
最终:
16库 × 64表
=
1024分片
29. 雪花ID + Hash 分片
现在很多互联网系统使用。
例如:
订单ID:
Snowflake:
184729384729384
然后:
hash(order_id)%16
得到:
db7
优点:
ID趋势递增。
分片均衡。
30. 各种算法对比
| 算法 | 核心思想 | 优点 | 缺点 | 适合 |
|---|---|---|---|---|
| Hash取模 | hash(key)%N | 简单均衡 | 扩容困难 | 固定规模系统 |
| 一致性哈希 | Hash环 | 扩容影响小 | 实现复杂 | 缓存、节点动态变化 |
| Range | 范围划分 | 范围查询快 | 热点明显 | 日志、时间数据 |
| Time | 按时间 | 冷热分离 | 最新热点 | 时序数据 |
| Directory | 映射表 | 灵活 | 依赖中心服务 | 复杂业务 |
| Composite | 组合 | 能力强 | 复杂 | 大型互联网 |
31. ShardingSphere里面如何实现这些算法?
ShardingSphere把算法抽象成:
Sharding Algorithm
主要类型:
32. Standard
精确:
=
范围:
between
例如:
user_id=100
33. Complex
同时使用多个字段。
例如:
user_id
+
order_id
34. Hint
不根据SQL字段。
由业务指定。
例如:
强制访问db3
35. None
不分片。
36. 结合云数据库运维理解
对于云数据库平台,真正重要的是:
不是选择哪个算法,而是:
如何根据业务负载动态选择和调整算法。
例如:
监控发现:
shard_01
CPU:
95%
QPS:
10万
shard_02
CPU:
30%
QPS:
2万
系统应该判断:
原因:
可能:
分片键选择不合理
或者
数据倾斜
然后:
自动执行:
热点检测
↓
重新分片
↓
数据迁移
↓
更新路由规则
这就是未来 AIOps 数据库治理方向。
如果继续深入,下一步建议学习 “ShardingSphere 分片源码设计:分片规则、路由引擎、SQL改写和执行引擎源码流程”,因为它和 Kubernetes Scheduler 的调度思想非常接近。
关联文档
- MySQL 基础:MySQL 数据库基础与运维入口。
