本文关于MySQL分库分表设计的详细技术解析,涵盖核心原则、策略及实践案例:
一、为什么需要分库分表?
当单表数据量超过500万行或数据库QPS达到**2000+**时,MySQL单机性能会显著下降,具体表现为:
- 查询延迟增加:B+树层级变深,索引效率降低。
- 锁竞争加剧:高并发写入导致行锁/表锁冲突。
- 存储瓶颈:单机磁盘容量限制数据增长。
分库分表通过水平拆分(数据分散到多库多表)和垂直拆分(按业务拆分库)解决上述问题。
二、分库分表核心策略
2.1 垂直拆分
- 垂直分库:按业务模块划分数据库。
示例:电商系统拆分为order_db(订单库)、user_db(用户库)、product_db(商品库)。 - 垂直分表:将宽表按字段冷热分离。
示例:user表拆分为user_base(基础信息)和user_profile(详情信息)。
2.2 水平拆分
- 水平分库分表:将数据按规则分散到多个库或表中。
常用分片算法:
算法 | 优点 | 缺点 |
---|---|---|
哈希分片 | 数据均匀分布 | 扩容需重新哈希 |
范围分片 | 支持范围查询 | 可能产生数据倾斜 |
一致性哈希 | 扩容影响小 | 实现复杂度高 |
时间分片 | 按时间归档(如按月分表) | 历史数据访问效率低 |
分片键选择原则:
- 高频查询字段:如订单表的user_id或order_id。
- 数据分布均匀:避免倾斜导致热点库/表。
三、分库分表设计步骤
3.1 需求评估
- 数据量预估:当前数据量、年增长率(如每日新增100万订单)。
- 业务场景:OLTP(高并发事务)或OLAP(复杂查询)。
- 拆分目标:降低单表压力 or 实现多租户隔离。
3.2 分片方案设计
示例:电商订单表水平分库分表
- 分片键:user_id(按用户查询订单频率最高)。
- 分片算法:user_id % 64(哈希取模,分为64张表)。
- 分库策略:每8张表归属一个库,共8个库(order_db_0 ~ order_db_7)。
路由规则:
```java
// 计算分库分表位置
int dbIndex = (userId % 64) / 8; // 库编号:0~7
int tableIndex = userId % 64; // 表编号:0~63
String sql = "SELECT * FROM order_db_" + dbIndex + ".order_" + tableIndex;
3.3 数据迁移方案
- 双写过渡:
- 旧库持续写入,同时新库通过Binlog同步增量数据。
- 使用DataX或Spark迁移历史数据。
- 流量切换:
- 校验数据一致性后,逐步将查询流量切至新库。
四、分库分表中间件选型
工具 | 特点 |
---|---|
ShardingSphere | Apache顶级项目,支持读写分离、分布式事务,透明化分片(JDBC代理模式)。 |
MyCAT | 基于Proxy的中间件,配置灵活,适合复杂分片规则。 |
Vitess | YouTube开源,Kubernetes友好,适合云原生环境。 |
ShardingSphere配置示例:
rules:
- !SHARDING
tables:
order:
actualDataNodes: order_db_${0..7}.order_${0..63}
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: db_hash_mod
tableStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: table_hash_mod
shardingAlgorithms:
db_hash_mod:
type: HASH_MOD
props:
sharding-count: 8
table_hash_mod:
type: HASH_MOD
props:
sharding-count: 64
五、挑战与解决方案
5.1 跨分片查询
- 全局二级索引:
使用Elasticsearch同步订单ID与用户ID,解决非分片键查询(如按订单号查)。 - 异步聚合:
分页查询时,各分片并行执行,结果集在内存合并(需限制页码深度)。
5.2 分布式事务
- 柔性事务:
- Seata AT模式:基于undo_log实现最终一致性。
- 本地消息表:业务侧保证消息可靠投递。
5.3 扩容与再平衡
- 动态扩容:
从8库扩容到16库时,采用一致性哈希算法,仅迁移部分数据。 - 自动化工具:
使用pt-online-schema-change在线修改分片规则。
六、最佳实践
- 避免过度分片:单表保持在500万~1000万行。
- 冷热分离:将历史数据归档至ClickHouse等列存数据库。
- 监控告警:关注分片倾斜率、慢查询、连接池水位。
- 单元化部署:按地域分库,减少跨机房调用(如华东/华北集群)。
结语
分库分表是提升数据库扩展性的有效手段,但需结合业务特点选择分片策略。借助成熟中间件(如ShardingSphere)可降低开发复杂度,同时需在一致性、复杂查询与运维成本间做好权衡。