分库分表演进路线
不要一步到位
分库分表不是架构的起点,而是随着业务增长逐步演进的结果。盲目的”一步到位”只会引入不必要的复杂度。
一个健康的数据库架构演进路线通常是这样的:
单库单表 → 读写分离 → 垂直拆分 → 水平拆分 → 分布式数据库
第 0 阶段:单库单表
状态
- 所有业务数据在一个数据库实例中
- QPS < 3000,数据量 < 500 万行
- SQL 走索引,查询基本在毫秒级
优化方向
- SQL 优化(避免 SELECT *)
- 索引优化(慢查询 + explain)
- 配置优化(buffer pool 调大、日志配置)
- 缓存引入(Redis 缓存热点数据)
前置条件:
-- 完成了基本的 SQL 优化
-- 慢查询已经被消灭
-- EXPLAIN 分析过所有主要查询
第 1 阶段:读写分离
触发条件
- 单库 QPS 超过 3000,且以读负载为主
- 主库 CPU 使用率超过 70%
- 慢查询集中于读取操作
架构
应用层
├── 主库(Master):处理 INSERT/UPDATE/DELETE
└── 从库(Slave1、Slave2):处理 SELECT
关键点
- 主从同步延迟的监控和兜底
- 关键业务读走主库(如支付结果)
- 使用 ProxySQL 或 Atlas 管理读写分离
退出条件
- 单表数据量超过 1000 万
- 写入 TPS 持续增长,主库 CPU/IO 打满
- 即使加了缓存,读压力仍然大
第 2 阶段:垂直拆分
触发条件
- 单一数据库包含多个业务模块
- 业务增长导致相互干扰(订单影响用户查询)
- 单表字段数过多(> 30 个字段)
架构
user_db(用户模块)→ 独立实例
order_db(订单模块)→ 独立实例
product_db(商品模块)→ 独立实例
关键点
- 按业务域拆分,每个库独立部署
- 梳理跨库 JOIN 场景,决策是用应用层聚合还是数据冗余
- 分布式事务在跨库场景中显式处理
退出条件
- 某一张表(如 order)数据量超过 1000 万
- 单表写入 QPS 超过单机处理能力
- 单表数据文件超过 TB 级别
第 3 阶段:水平拆分
触发条件
- 某张表数据量超过 500 万-2000 万
- 单表写入成为瓶颈
- 数据文件大小影响备份和恢复
架构
order_db_0 order_db_1
├── order_0 ├── order_2
├── order_1 └── order_3
关键决策
- 分片键选择:选择最常作为查询条件的字段
- 分片算法:哈希分片(均匀)还是范围分片(方便扩容)
- 分片数量:预留 2-3 年的增长空间
- 中间件:Sharding-JDBC / ShardingSphere-Proxy
需要解决的问题
- 全局唯一 ID(雪花算法)
- 跨分片查询(应用层聚合 / ES)
- 分布式事务(TCC / SEATA)
- 分页排序(游标分页)
第 4 阶段:分布式数据库
触发条件
- 分库分表带来的复杂度已超出团队承受能力
- 需要更强大的查询能力和实时分析能力
- 需要更好的弹性扩展
可选方案
- TiDB:兼容 MySQL 协议的分布式 NewSQL
- OceanBase:蚂蚁金服自研分布式数据库
- PolarDB-X:阿里云的分布式数据库
优势
- 原生支持分布式事务
- 支持跨库 JOIN 和复杂查询
- 自动扩缩容,无需手动迁移数据
- 兼容 MySQL 协议,代码改动小
演进路线的核心原则
- 只处理当前的问题:不要在架构上没有痛点时超前演进
- 每次演进解决一个核心问题:不要同时引入多个变化
- 保持回退能力:每个阶段的架构都要能回退到上一阶段
- 控制拆分粒度:不是所有表都需要分表,20% 的表承担 80% 的压力
- 渐进式切换:先灰度验证,再全量切换
规模参考
| 数据规模 | 推荐架构 |
|---|---|
| 日活 1 万,数据量 < 500 万 | 单库单表 |
| 日活 10 万,数据量 500-5000 万 | 读写分离 |
| 日活 100 万,数据量 5000 万-1 亿 | 垂直拆分 + 读写分离 |
| 日活 500 万+,数据量 > 1 亿 | 水平拆分 |
| 日活 1000 万+,数据量 > 5 亿 | 分布式数据库 / 自研分片架构 |
面试要点
- 演进路线是”逐步升级”而非”一步到位”——这是架构设计的分寸感
- 每阶段都有触发条件和退出条件,不是拍脑袋决定的
- 能讲清楚自己在每个阶段做了什么优化
- 深刻理解:分库分表带来的复杂度远大于读写分离和垂直拆分
- 有时候直接用分布式数据库(TiDB)比自研分片架构更明智
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END


暂无评论内容