1. 分库分表概述
分库分表是数据库架构设计中解决数据量增长问题的核心方案。当单表数据量达到千万级甚至亿级时,传统的单库单表架构会遇到性能瓶颈,此时就需要考虑分库分表技术。
1.1 什么是分库分表
分库分表是将一个数据库中的数据分散到多个数据库(分库)或多个表(分表)中的技术方案。通过这种方式,可以将数据分散存储,减轻单个数据库或表的压力,提高系统的整体性能和扩展性。
分库分表主要解决以下问题:
- 单表数据量过大导致的查询性能下降
- 数据库连接数不足
- 单机存储容量限制
- 高并发下的IO瓶颈
1.2 分库分表的适用场景
分库分表并非适用于所有场景,通常需要考虑以下指标:
- 单表数据量超过500万行
- 数据库服务器CPU使用率长期高于70%
- 磁盘IO成为系统瓶颈
- 业务有明显的增长趋势
2. 分库分表的核心设计思路
2.1 水平拆分与垂直拆分
分库分表主要有两种拆分方式:
水平拆分(Horizontal Sharding)
将同一个表的数据按行拆分到不同的数据库或表中。例如,用户表可以按照用户ID的范围进行拆分:
- 用户ID 1-100万存储在表user_1
- 用户ID 100万-200万存储在表user_2
垂直拆分(Vertical Sharding)
将同一个表的不同字段拆分到不同的表中。例如,将用户基本信息与用户扩展信息分开存储:
- 用户表存储核心信息(ID、用户名、密码)
- 用户详情表存储扩展信息(地址、爱好等)
2.2 分片键的选择
分片键(Sharding Key)是决定数据如何分布的关键字段。选择合适的分片键需要考虑:
- 数据分布均匀性:确保数据能均匀分布在各个分片上
- 查询效率:常用查询条件应包含分片键
- 业务特性:避免跨分片事务
常见的分片键选择:
- 用户ID
- 订单ID
- 时间范围
- 地理位置
3. 分库分表的技术实现
3.1 分库分表方案对比
| 方案类型 | 代表产品 | 优点 | 缺点 |
|---|---|---|---|
| 客户端分片 | MyBatis分片插件 | 实现简单,无需中间件 | 业务侵入性强,升级困难 |
| 代理层分片 | MyCat、ShardingSphere-Proxy | 对应用透明,易于维护 | 性能开销大,单点风险 |
| 驱动层分片 | Sharding-JDBC | 性能好,无单点 | 需要适配不同语言 |
3.2 ShardingSphere实战配置
以Sharding-JDBC为例,配置分库分表规则:
yaml复制spring:
shardingsphere:
datasource:
names: ds0,ds1
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/db0
username: root
password: 123456
ds1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/db1
username: root
password: 123456
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..15}
table-strategy:
inline:
sharding-column: order_id
algorithm-expression: t_order_$->{order_id % 16}
database-strategy:
inline:
sharding-column: user_id
algorithm-expression: ds$->{user_id % 2}
3.3 分布式ID生成方案
分库分表后,传统的自增ID不再适用,需要采用分布式ID方案:
-
UUID
- 优点:实现简单
- 缺点:无序,影响索引性能
-
Snowflake算法
- 结构:1位符号位 + 41位时间戳 + 10位机器ID + 12位序列号
- 优点:趋势递增,性能好
- 缺点:依赖时钟同步
-
数据库号段模式
- 原理:预分配ID段,减少数据库访问
- 适合场景:中小规模应用
4. 分库分表的挑战与解决方案
4.1 跨库JOIN问题
解决方案:
- 字段冗余:将关联字段冗余到主表
- 数据异构:通过消息队列同步数据
- 应用层JOIN:先查询主表,再批量查询关联表
4.2 分布式事务
常用方案对比:
| 方案 | 原理 | 适用场景 |
|---|---|---|
| XA协议 | 两阶段提交 | 强一致性要求高 |
| TCC | Try-Confirm-Cancel | 高并发场景 |
| SAGA | 长事务拆分 | 业务流程长 |
| 本地消息表 | 异步确保 | 最终一致性 |
4.3 分页查询优化
跨分片分页的解决方案:
- 全局排序法:各分片排序后合并
sql复制SELECT * FROM t_order ORDER BY create_time DESC LIMIT 10000, 10 - 二次查询法:先查ID,再查详情
- 分片键连续法:利用分片键的有序性
5. 分库分表的最佳实践
5.1 容量规划建议
- 单表建议控制在500万行以内
- 单个分片数据量不超过服务器内存的50%
- 预留20%的容量缓冲
5.2 监控指标
关键监控项:
- 分片数据分布均衡性
- 慢查询比例
- 连接池使用率
- 磁盘IOPS
5.3 常见踩坑点
- 分片键选择不当:导致数据倾斜
- 未考虑扩容:分片数固定,难以扩展
- 过度设计:小数据量过早分片
- 忽略事务边界:跨分片事务性能差
6. 分库分表的未来演进
随着云原生技术的发展,分库分表方案也在进化:
- Serverless数据库:自动弹性扩展
- 分布式NewSQL:TiDB、CockroachDB等
- 云原生中间件:更轻量的Proxy方案
在实际项目中,我们采用分库分表后,订单查询性能提升了8倍,TPS从原来的500提升到了4000。关键是要根据业务特点选择合适的拆分策略,并做好充分的测试验证。
