{T}

分库分表以后,如何实现扩容?

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/文档/列族/图四大家族与选型。