一、为什么需要分库分表?
随着业务规模的增长,单库单表逐渐暴露出性能瓶颈:
- 数据量过大:单表存储超过1亿条数据时,查询效率显著下降。
- 并发压力高:单一数据库的QPS(每秒查询数)难以支撑高并发场景。
- 维护困难:备份、恢复等运维操作耗时增加,影响业务连续性。
典型问题场景:
- 电商订单表日增百万数据,单表无法支撑。
- 用户行为日志表年增数十TB,存储成本飙升。
- 实时风控系统要求毫秒级响应,传统架构难以满足。
二、分库分表核心策略
1. 垂直拆分 vs 水平拆分
- 垂直拆分:
- 按业务拆分:将用户表、订单表等不同业务表拆分到不同数据库。
- 按字段拆分:将大字段(如JSON、BLOB)单独存储,减少主表压力。
- 水平拆分:
- 范围分片:按时间或ID范围划分数据(如按月份分表)。
- 哈希分片:通过哈希算法均匀分布数据(如按用户ID取模)。
2. 常用分片算法对比
算法 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
范围分片 | 易于扩容 | 数据分布不均 | 时间序列数据 |
哈希取模 | 数据分布均匀 | 扩容复杂 | 通用场景 |
一致性哈希 | 扩容影响小 | 实现复杂 | 动态扩容场景 |
地理位置分片 | 符合业务特性 | 需要业务适配 | 本地生活服务 |
三、实战:SpringBoot+ShardingSphere实现分库分表
场景:电商订单表水平分片(2库×2表)
1. 数据库规划
-
分片键:
user_id
(用户ID) -
分片策略:
user_id % 4
-
分布式ID:雪花算法生成唯一订单ID
2. ShardingSphere配置
spring:
shardingsphere:
datasource:
names: ds0,ds1
ds0:
url: jdbc:mysql://db0:3306/order
username: root
password: 123456
ds1:
url: jdbc:mysql://db1:3306/order
username: root
password: 123456
rules:
sharding:
tables:
order:
actual-data-nodes: ds$->{0..1}.order_$->{0..1}
database-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: db-sharding
table-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: table-sharding
sharding-algorithms:
db-sharding:
type: INLINE
props:
algorithm-expression: ds$->{user_id % 2}
table-sharding:
type: INLINE
props:
algorithm-expression: order_$->{user_id % 2}
三、生产环境进阶方案
1. 热点数据解决方案
- 复合分片键:结合用户ID和时间戳分散数据。
- 动态扩容:通过一致性哈希减少数据迁移量。
2. 数据迁移工具选型
工具 | 原理 | 适用场景 |
---|---|---|
ShardingScaling | 解析binlog同步 | MySQL在线迁移 |
DataX | 多线程批处理 | 异构数据源 |
3. 监控体系搭建
- 核心指标:分片查询延迟、连接池使用率、数据均衡性。
- 工具集成:Prometheus监控+Granfana可视化看板。
四、典型问题与解决案例
案例1:分页排序混乱
- 问题:跨分片排序结果不一致。
- 解决:使用业务主键(如订单ID)作为游标,保证顺序。
案例2:分布式事务不一致
- 问题:跨库更新导致数据不一致。
- 解决:引入Seata框架实现分布式事务。
五、总结与未来趋势
核心原则:
- 分片键选择:高离散度+业务相关性。
- 渐进式扩容:预留至少2倍扩容能力。
- 监控先行:建立完善的指标监控体系。
未来方向:
- 云原生数据库:TiDB、CockroachDB支持自动分片。
- 智能分片:AI预测数据分布,动态调整分片策略。
推荐工具与资源
- 工具:ShardingSphere、MyCAT、DataX。
- 书籍:《高性能MySQL》《分布式系统架构设计》。