数据迁移、扩缩容方案
为什么数据迁移如此棘手
分库分表后,数据迁移是一个绕不开的问题。当数据量增长超过预期、分片策略需要调整、或者硬件需要升级时,都需要对已有数据进行迁移。
主要挑战在于:
– 数据量大:可能已经积累了数十 TB 的数据
– 服务不能停:业务需要 7×24 运行
– 一致性要求高:不能丢失或重复数据
常见的扩缩容场景
| 场景 | 原因 | 动作 |
|---|---|---|
| 分片扩容 | 数据量超过预期 | 从 64 个分片 → 128 个分片 |
| 分片缩容 | 业务下线或合并 | 减少分片数 |
| 分片键变更 | 原分片键不合理 | 切换为新分片键 |
| 数据库迁移 | 硬件升级、机房搬迁 | 从旧集群迁移到新集群 |
| 版本升级 | MySQL 大版本升级 | 数据导出导入 |
设计方案一:停服迁移
步骤
- 发布停服公告,停止所有写操作
- 导出旧表数据
- 导入新表并建立索引
- 验证数据一致性
- 切换 DNS/配置到新数据源
- 恢复服务
优点
- 实现简单,不需要复杂的同步逻辑
- 数据一致性好,迁移期间没有变更
缺点
- 服务不可用时间较长(数小时甚至数天)
- 对于 7×24 业务不可接受
设计方案二:双写迁移
步骤
阶段一:双写 + 全量同步
1. 新、旧两套分片集群同时启动
2. 应用代码修改:写入操作同时写入旧集群和新集群
3. 开启历史数据全量同步(从旧集群批量导入新集群)
4. 持续校验数据一致性
阶段二:增量追平
1. 全量完成后,新旧数据差异只有双写阶段的增量
2. 通过对比差异表或 binlog 同步补全
3. 确认新旧集群数据完全一致
阶段三:切换
1. 将读流量逐步切到新集群(灰度切量)
2. 观察监控:延迟、错误、慢查询
3. 确认无误后关闭双写旧集群
4. 下线旧集群
优点
- 零停机,业务无感知
- 支持灰度验证,风险可控
缺点
- 实现复杂,代码需要支持双写
- 双写期间写入性能下降(每次写操作翻倍)
- 需要额外的数据校验工具
设计方案三:binlog 同步迁移
步骤
- 搭建新集群
- 使用 Canal / Maxwell 订阅旧集群的 binlog
- binlog 实时同步到新集群(本质是 MySQL 复制)
- 历史数据通过 select 批量导入
- 全量同步完成后,binlog 会追平增量
- 追齐后切换读写流量
示意图
旧集群(源) ←写入← 应用
│
├── 全量同步(SELECT INTO + INSERT)
│ ↓
新集群(目标) ←接收← Canal binlog 增量
│
└── 校验一致后,应用切换到新集群
优点
- 代码零侵入(不需要改应用代码)
- 支持实时同步,延迟可控在秒级
缺点
- 需要部署 Canal 等同步组件
- 需要额外处理 DDL 变更的同步
- binlog 格式必须是 ROW 模式
哈希分片扩容的特殊问题
范围分片扩容简单——新加的分片分配新的 ID 范围即可,旧分片完全不动。
哈希分片扩容则棘手得多。假设从 64 个分片扩容到 128 个分片:
旧规则:shard = id % 64
新规则:shard = id % 128
原来分在 0 号分片的记录,新规则下可能分到 0 或 64 号分片,需要重新计算并迁移。
解决方案:
- 一致性哈希:减少迁移量
- 虚拟分片法:提前分成 1024 个虚拟分片,物理上映射到 64 个库;扩容时调整映射关系,只迁移部分虚拟分片
- 先按余数分片再二级映射:分片编号不变,底层迁移部分数据
数据一致性校验
无论哪种方案,迁移后都需要校验数据一致性。
校验工具:
– 全量校验:CHECKSUM TABLE 对比
– 抽样校验:按 mod 取一定比例的数据对比
– 差量校验:对比新旧集群的最后修改时间
最佳实践建议
- 尽可能避免迁移:一开始就预留足够的分片数(如 128 或 256),而非频繁扩容
- 先按 2 的幂次分片:后续扩容时可以从 128 → 256,迁移邻居表相对可控
- 灰度切换:不要一刀切,先切 1% 流量验证,逐步放大到 100%
- 回滚预案:切换前保留旧集群,一旦发现问题随时切回
- 观察期:切换后至少观察一天再下线旧集群
总结
数据迁移的核心挑战在于不停机和数据一致性。双写迁移和 binlog 同步是最常用的不停机方案,各有优缺点。与其追求完美的迁移方案,不如在一开始就做好分片数量的规划和预估,尽量减少迁移次数。


暂无评论内容