分库分表以后,如何实现扩容?
0. 引言
分库分表的分片数是规划时定的,但业务增长可能超出预期:4 库不够要 8 库、8 库不够要 16 库。扩容的难点不是加机器,而是已有数据如何迁移到新分片——取模分片下,分片数 N 变化,几乎所有数据的路由都会改变。本文讲解扩容的核心矛盾与三种主流方案,重点是可落地的平滑扩容流程。
1. 扩容的本质难点
text
取模分片:shard = id % 4
扩容到 8:shard = id % 8
结果:id % 4 == 0 的数据可能路由到 0 或 4 —— 几乎所有数据都要迁移!| 方案 | 迁移量 | 停机 | 复杂度 |
|---|---|---|---|
| 翻倍扩容 | 约 50% | 可不停机 | 中 |
| 一致性哈希 | 仅 1/N | 无需迁移 | 高(路由复杂度) |
| 双写迁移 | 100% 增量 | 无 | 高 |
2. 方案一:翻倍扩容(最常用)
关键洞察:分片数从 N → 2N 时,id % 2N 的结果要么不变(id % N),要么加上 N——数据只会在"原分片"与"原分片 + N"两个位置之间移动。
text
原 4 库:db0(db0) db1 db2 db3
扩容 8 库:db0 的数据分流到 db0 和 db4;db1 分流到 db1 和 db5;……
迁移量 = 50%,且每份数据只搬一次步骤:
text
① 新建 4 个新库(db4~db7),结构一致
② 停止写入(或双写),按规则迁移:db_i 中 id%8==i 的留在原库,其余搬入 db_{i+4}
③ 校验数据一致性(行数/抽样/checksum)
④ 切换路由配置(4 库 → 8 库),灰度放量
⑤ 观察无误后清理临时状态为什么翻倍而非"加 1 个库"?
N → N+1时,id % (N+1)与id % N无规律,几乎 100% 数据都要迁移;翻倍只搬 50%,且迁移规则简单可校验。
3. 方案二:一致性哈希(扩容友好型路由)
text
哈希环:0 ~ 2^32-1 的圆环,节点(库)与数据都哈希到环上
数据归属:顺时针遇到的第一节点
扩容:新增节点只影响其逆时针方向到上一节点之间的数据(约 1/N)- 扩容只影响少量数据,无需全量重算;
- 代价:范围查询/顺序遍历不友好(数据散落无规律)、虚拟节点管理复杂;
- 适用:缓存分片(Redis Cluster)、非关系型数据;MySQL 分片场景用较少(排序/聚合本来就是痛点)。
4. 方案三:双写迁移(不停机平滑迁移)
适用于分片数不变、数据搬迁(如换机房、换中间件、取模改一致性哈希):
图表渲染中…
| 步骤 | 说明 |
|---|---|
| ① 双写 | 应用层同时写新旧库(新库失败不影响主流程,记录补偿日志) |
| ② 全量迁移 | 历史数据按主键分批搬运(SELECT ... id > ? LIMIT 1000 循环) |
| ③ 增量追平 | 迁移期间的新数据靠双写 + 补偿任务追平 |
| ④ 对账校验 | 行数、checksum、抽样对比,修复不一致 |
| ⑤ 灰度切换 | 读流量 1% → 10% → 50% → 100% |
| ⑥ 收尾 | 停双写、清理补偿任务、旧库保留观察期 |
双写是"老数据搬家 + 新数据分身"的通用方法论,同样适用于:ES 重建索引、缓存预热、机房迁移、换存储引擎。
5. 扩容的通用最佳实践
- 提前演练:灰度环境完整跑一遍迁移流程,记录耗时与数据量;
- 可回滚:路由配置切换保留旧版本,出错一键回切(Apollo/Nacos 配置灰度);
- 校验优先:迁移完成先校验再放量,数据一致性是唯一硬指标;
- 容量规划:扩容后预留 30%+ 余量,避免短期再次扩容;
- 自动化:迁移脚本幂等可重跑(主键分批 + 断点续传)。
6. 小结
- 扩容痛点:取模分片下分片数变化导致数据重路由;
- 三方案:翻倍扩容(迁移 50%、规则简单,最常用)、一致性哈希(迁移少但路由复杂)、双写迁移(通用平滑搬迁);
- 平滑扩容六步:双写 → 全量迁移 → 追平 → 对账 → 灰度切换 → 收尾;
- 硬性要求:可回滚、可校验、可重跑、先演练。
下一章讲解 NoSQL 数据库的典型应用:KV/文档/列族/图四大家族与选型。