MySQL 分片
MySQL 分片(Sharding)的本质是:将一个逻辑上的大数据库拆分成多个物理数据库实例,让数据分散存储和访问,从而突破单机 MySQL 在容量、并发和性能上的瓶颈。
对于运维和云平台方向来说,理解分片不能只停留在“数据拆开了”,还需要理解为什么拆、怎么定位数据、查询怎么执行、带来的问题是什么。
1. 为什么需要 MySQL 分片
单机 MySQL 的能力存在上限。
假设有一个订单表:
CREATE TABLE orders(
id BIGINT PRIMARY KEY,
user_id BIGINT,
amount DECIMAL(10,2),
create_time DATETIME
);
随着业务增长:
订单量:
1000万
↓
1亿
↓
10亿
↓
100亿
单机可能出现:
1.1. 存储瓶颈
一台机器:
磁盘:
2TB
订单数据:
5TB
无法存储。
1.2. IO 瓶颈
大量查询:
select *
from orders
where user_id=10001;
大量写入:
insert into orders...
都会竞争:
磁盘IO
CPU
Buffer Pool
Redo Log
Binlog
1.3. 并发瓶颈
例如:
10万个请求/s
全部访问:
mysql-01
|
orders表
单点压力巨大。
所以需要:
应用
|
分片中间件
|
----------------------
| | |
mysql-01 mysql-02 mysql-03
订单1 订单2 订单3
2. 分片的核心思想
假设原来:
orders表
id
1
2
3
4
5
6
7
8
9
10
全部在:
mysql-01
分片后:
mysql-01
1
2
3
mysql-02
4
5
6
mysql-03
7
8
9
10
应用访问时:
用户请求
|
|
判断数据在哪个库
|
|
访问对应MySQL
这个“判断规则”叫:
分片算法(Sharding Algorithm)
genui{“data_networks_databases_learning_block”:{“type_id”:“SQL_GROUP_BY”}}
3. 分片的三个关键概念
4. 分片键(Sharding Key)
决定数据放哪里的字段。
例如:
用户系统:
user
{
id,
name,
phone
}
选择:
user_id
作为分片键。
原因:
用户相关数据天然绑定:
user_id=10001
订单
支付
购物车
地址
都可以放一起。
5. 分片规则
例如:
有4个数据库:
db0
db1
db2
db3
规则:
database = user_id % 4
例如:
用户:
10001
计算:
10001 % 4 = 1
所以:
db1
存储:
user_id=10001
整体:
user_id
10000
|
10000%4=0
db0
10001
|
10001%4=1
db1
10002
|
10002%4=2
db2
6. 常见 MySQL 分片方式
主要有三种。
7. 水平分片(Horizontal Sharding)
最常见。
也叫:
分库分表
特点:
表结构一样,数据不同。
例如:
原来:
user_order
10亿行
拆:
order_db_0
2.5亿
order_db_1
2.5亿
order_db_2
2.5亿
order_db_3
2.5亿
每个库:
orders表
结构完全一样。
例如:
订单id
10001
计算:
10001 % 4 = 1
进入:
order_db_1.orders
优点:
-
数据量下降
-
IO下降
-
查询压力下降
缺点:
- 跨库查询困难
例如:
以前:
select count(*)
from orders;
现在:
需要:
db0 count
+
db1 count
+
db2 count
+
db3 count
8. 垂直分片(Vertical Sharding)
按照业务拆。
例如:
原来:
用户库
user
order
payment
message
拆:
用户服务
user_db
user表
订单服务
order_db
order表
支付服务
payment_db
payment表
类似微服务数据库拆分。
优点:
业务隔离。
例如:
支付压力大:
只扩容:
payment_db
不用影响用户。
缺点:
业务关联查询复杂。
例如:
订单:
order
user_id
查询:
订单+用户信息
以前:
join
现在:
跨数据库:
order_db
|
|
RPC
|
user_db
9. 混合分片
大型互联网通常:
水平 + 垂直一起使用。
例如:
淘宝:
用户域
|
user_db
水平拆
user_db_0
user_db_1
订单域
order_db
水平拆
order_db_0
order_db_1
10. 分片以后 SQL 怎么执行?
这是最关键的问题。
以前:
select *
from orders
where user_id=10001;
MySQL:
直接执行。
分片以后:
应用首先计算:
user_id=10001
10001%4=1
知道:
order_db_1
然后:
发送:
select *
from order_db_1.orders
where user_id=10001;
这个过程叫:
路由(Routing)
11. 分片中间件
业务不可能每个人手写:
user_id % 4
所以出现中间件。
常见:
12. Apache ShardingSphere
架构:
应用
|
|
ShardingSphere
|
----------------
| | |
DB0 DB1 DB2
它负责:
-
SQL解析
-
分片路由
-
SQL改写
-
结果合并
例如:
用户:
select *
from orders
where user_id=10;
ShardingSphere:
分析:
user_id=10
10%4=2
改写:
select *
from db2.orders
where user_id=10;
13. Mycat
老牌分库分表中间件。
14. 分片最大的问题
很多人认为:
分片解决所有性能问题。
实际上:
分片引入大量复杂性。
15. 跨分片查询
例如:
查询:
select *
from orders
where create_time>'2026-01-01';
没有:
user_id
怎么办?
不知道在哪个库。
只能:
广播:
db0查询
db1查询
db2查询
db3查询
然后合并。
这叫:
Scatter-Gather
性能很差。
16. 分片扩容问题
假设:
原来:
4个库
规则:
user_id % 4
现在:
增加:
8个库
规则变:
user_id % 8
大量数据位置改变。
例如:
以前:
10001 %4=1
现在:
10001%8=1
有些幸运,但大量数据都会变化。
解决:
16.1. 一致性哈希
或者:
16.2. 预留分片
例如:
提前:
1024个逻辑分片
然后映射:
逻辑分片
|
物理数据库
扩容只迁移部分。
17. 主键问题
以前:
AUTO_INCREMENT
每个库:
1
2
3
会冲突。
所以需要:
17.1. UUID
例如:
550e8400-e29...
缺点:
UUID随机:
索引性能差。
17.2. 雪花算法 Snowflake
现在比较常见:
时间戳
+
机器ID
+
序列号
生成:
180923847239847
特点:
-
全局唯一
-
趋势递增
18. MySQL 分片和主从复制有什么区别?
很多运维容易混淆。
19. 主从复制
解决:
读压力
结构:
写
|
master
|
--------------
| |
slave1 slave2
数据:
完全一样。
20. 分片
解决:
数据量
+
写压力
结构:
db0
数据A
db1
数据B
db2
数据C
数据:
不同。
实际生产:
通常组合:
应用
|
分片中间件
|
--------------------------------
| | |
订单库0 订单库1 订单库2
master master master
|
slave slave slave
21. 对云数据库运维来说,需要掌握哪些?
结合你的云运维和 AIOps 方向,我认为重点不是手写分片,而是理解:
22. (必须)
掌握:
- 水平分片
- 垂直分片
- 分片键选择
- 分片路由
- 主从复制区别
- 分片带来的运维问题
23. (生产运维)
需要理解:
- ShardingSphere架构
- MySQL Router
- ProxySQL
- 数据迁移
- 分片扩容
- 热点分片
- 分片倾斜
例如:
某个用户:
user_id=888888
特别活跃:
订单100亿
导致:
db2 CPU 100%
其他库20%
这就是:
分片热点(Hot Sharding)
也是云数据库平台需要自动检测的问题。
24. (AIOps方向)
你以后做 AIOps,可以针对:
每个分片节点
CPU
IOPS
QPS
TPS
Buffer Pool
锁等待
复制延迟
慢SQL
建立:
异常检测
预测
自动迁移
自动扩容
关联文档
- MySQL 基础:MySQL 数据库基础与运维入口。
