跳到主要内容

分库分表扩容迁移流程解析

一、扩容流程概览

扩容方案:从2库×4表(8个物理分片)扩展到2库×8表(16个物理分片)

涉及表类型

  • 订单表(d_order):4张 → 8张

核心思想

  • 每张原表拆分为2张表
  • 原表保留前半部分数据(64个虚拟分片)
  • 后半部分数据迁移到对应的新表(64个虚拟分片)
  • 虚拟分片总数保持1024不变,但每个物理分片对应的虚拟分片数从128个减少到64个
┌──────────────────────────────────────────────────────────────────┐
│ 初始状态(2库×4表=8个物理分片) │
│ ┌─────────────┬───────────────────────────────────────────────┐│
│ │ 物理分片0 │ 虚拟分片0-127 → damai_order_0.d_order_0 ││
│ │ 物理分片1 │ 虚拟分片128-255 → damai_order_0.d_order_1 ││
│ │ 物理分片2 │ 虚拟分片256-383 → damai_order_0.d_order_2 ││
│ │ 物理分片3 │ 虚拟分片384-511 → damai_order_0.d_order_3 ││
│ │ 物理分片4 │ 虚拟分片512-639 → damai_order_1.d_order_0 ││
│ │ 物理分片5 │ 虚拟分片640-767 → damai_order_1.d_order_1 ││
│ │ 物理分片6 │ 虚拟分片768-895 → damai_order_1.d_order_2 ││
│ │ 物理分片7 │ 虚拟分片896-1023 → damai_order_1.d_order_3 ││
│ └─────────────┴───────────────────────────────────────────────┘│
│ │
└──────────────────────────────────────────────────────────────────┘

【扩容决策】

每张原表拆分为2张表,后半部分数据迁移到新表
例如:d_order_0 拆分为 d_order_0(0-63) + d_order_4(64-127)

┌──────────────────────────────────────────────────────────────────┐
│ 步骤1:创建新物理表 │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ 在现有库中创建新表(每个库每个表类型从4张扩展到8张): │
│ │
│ 1.1 订单表(d_order) │
│ CREATE TABLE damai_order_0.d_order_4 LIKE damai_order_0.d_order_0; │
│ CREATE TABLE damai_order_0.d_order_5 LIKE damai_order_0.d_order_0; │
│ CREATE TABLE damai_order_0.d_order_6 LIKE damai_order_0.d_order_0; │
│ CREATE TABLE damai_order_0.d_order_7 LIKE damai_order_0.d_order_0; │
│ │
│ │
│ (同样在 damai_order_1 中创建所有表的_4-7版本) │
│ │
│ 结果:新表结构创建完成,数据为空 │
│ 从2库×4表扩展为2库×8表 │
└────────────────────────┬─────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│ 步骤2:迁移数据(重新分配数据) │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ 扩容前:8个物理分片,每个128个虚拟分片(1024÷8) │
│ 扩容后:16个物理分片,每个64个虚拟分片(1024÷16) │
│ │
│ 需要将每张原表拆分为两张表(3类表都需要拆分): │
│ ┌────────────────────┬─────────────────┬───────────────────┐ │
│ │ 原表 │ 保留在原表 │ 迁移到新表 │ │
│ ├────────────────────┼─────────────────┼───────────────────┤ │
│ │ d_order_0(0-127) │ 0-63 │ 64-127→d_order_4 │ │
│ │ d_order_1(128-255) │ 128-191 │ 192-255→d_order_5 │ │
│ │ d_order_2(256-383) │ 256-319 │ 320-383→d_order_6 │ │
│ │ d_order_3(384-511) │ 384-447 │ 448-511→d_order_7 │ │
│ │ │ │
│ └────────────────────┴─────────────────┴───────────────────┘ │
│ │
│ ⚠️ 核心策略:基于用户ID的虚拟分片ID进行迁移判断 │
│ 原因:订单号虽然包含用户ID基因位,但 orderNumber%128 ≠ userId%128 │
│ 如果按订单号判断,同一用户的订单会被分散到不同表 │
│ 解决:使用用户ID计算虚拟分片ID,保证同一用户的订单在同一表 │
│ │
│ 2.1 迁移 damai_order_0 库的订单表(d_order) │
│ 伪代码: │
│ for (Order order : damai_order_0.d_order_0.selectAll()) { │
│ // ⚠️ 关键:使用用户ID计算虚拟分片 │
│ int shardId = calculateLogicalShardId(order.getUserId());│
│ if (shardId >= 64 && shardId <= 127) { │
│ damai_order_0.d_order_4.insert(order); │
│ } │
│ } │
│ // 同理处理 d_order_1/2/3 → d_order_5/6/7 │
│ (同样处理 damai_order_1 库的所有表) │
│ │
│ 2.4 迁移进度 │
│ ┌──────────────────────────────────────────────────┐ │
│ │ ✓ d_order_0→d_order_4 │ │
│ │ ✓ d_order_1→d_order_5 │ │
│ │ ✓ d_order_2→d_order_6 │ │
│ │ ✓ d_order_3→d_order_7 │ │
│ │ damai_order_0库进度:100%(4张表迁移完成) │ │
│ │ 总进度:50%(damai_order_1库待处理) │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────────┬─────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│ 步骤3:数据验证 │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ 3.1 校验数据量(以d_order_0→d_order_4为例) │
│ 原表数据量(虚拟分片64-127):50,000条 │
│ 新表数据量:50,000条 │
│ ✓ 数据量一致 │
│ │
│ 3.2 校验所有迁移任务(damai_order_0库) │
│ ✓ d_order_0→d_order_4 │
│ ✓ d_order_1→d_order_5 │
│ ✓ d_order_2→d_order_6 │
│ ✓ d_order_3→d_order_7 │
│ (damai_order_1库同理,共8张表迁移完成) │
│ │
│ 3.3 业务验证 │
│ 在新表上执行典型查询,验证3类表功能正常 │
│ ✓ 订单查询功能正常 │
└────────────────────────┬─────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│ 步骤4:更新路由表(批量更新所有虚拟分片映射) │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ 更新虚拟分片64-127的路由(d_order_0的后半部分→d_order_4) │
│ UPDATE d_sharding_route_mapping │
│ SET physical_database = 'damai_order_0', │
│ physical_table = 'd_order_4', │
│ version = version + 1 │
│ WHERE logical_shard_id >= 64 AND logical_shard_id <= 127; │
│ │
│ 更新虚拟分片192-255的路由(d_order_1的后半部分→d_order_5) │
│ UPDATE d_sharding_route_mapping │
│ SET physical_table = 'd_order_5', │
│ version = version + 1 │
│ WHERE logical_shard_id >= 192 AND logical_shard_id <= 255; │
│ │
│ 更新虚拟分片320-383的路由(d_order_2的后半部分→d_order_6) │
│ ... (同理更新其他虚拟分片) │
│ │
│ 执行结果:512行受影响(8张原表×64个虚拟分片) │
└────────────────────────┬─────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│ 步骤5:刷新路由缓存 │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ 调用:routeManager.reloadRouteMapping() │
│ │
│ 操作: │
│ 1. 清空内存缓存 │
│ 2. 从数据库重新加载路由映射 │
│ 3. 重建缓存Map │
│ │
│ 结果:✓ 路由缓存更新完成 │
│ 新请求将自动路由到新表 │
└────────────────────────┬─────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│ 步骤6:灰度验证 │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ 6.1 监控查询请求 │
│ 虚拟分片64-127的查询是否路由到d_order_4 │
│ 虚拟分片192-255的查询是否路由到d_order_5 │
│ ✓ 路由正确 │
│ │
│ 6.2 监控性能指标 │
│ 新表查询响应时间:20ms(正常) │
│ 错误率:0% │
│ ✓ 性能正常 │
│ │
│ 6.3 观察期(建议24小时) │
│ 持续监控,确保无异常 │
│ ✓ 观察期正常 │
└────────────────────────┬─────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│ 步骤7:清理旧数据(可选) │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ 确认迁移完全成功后,删除源表中已迁移的数据 │
│ │
│ ⚠️ 核心策略:基于用户ID判断虚拟分片ID后删除 │
│ 保证与迁移逻辑一致,使用用户ID而非订单号 │
│ │
│ 伪代码: │
│ for (Order order : damai_order_0.d_order_0.selectAll()) { │
│ // ⚠️ 关键:使用用户ID计算虚拟分片(与迁移逻辑一致) │
│ int shardId = calculateLogicalShardId(order.getUserId()); │
│ if (shardId >= 64 && shardId <= 127) { │
│ damai_order_0.d_order_0.delete(order.id); // 已迁移到d_order_4 │
│ } │
│ } │
│ │
│ (同理清理d_order_1-3和damai_order_1库) │
│ │
│ ⚠️ 建议:先备份,再删除 │
└────────────────────────┬─────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│ 扩容完成! │
│ │
│ ┌──────────────────┬──────────────────────────────────────────┐│
│ │ damai_order_0库 │ 原12张表 → 扩展为24张表 ││
│ ├──────────────────┼──────────────────────────────────────────┤│
│ │ 订单表(d_order) ││
│ │ d_order_0 │ 虚拟分片0-63 (原0-127的前半部分) ││
│ │ d_order_1 │ 虚拟分片128-191(原128-255的前半部分) ││
│ │ d_order_2 │ 虚拟分片256-319(原256-383的前半部分) ││
│ │ d_order_3 │ 虚拟分片384-447(原384-511的前半部分) ││
│ │ d_order_4 (新) │ 虚拟分片64-127 (原0-127的后半部分)✓ ││
│ │ d_order_5 (新) │ 虚拟分片192-255 (原128-255的后半部分)✓││
│ │ d_order_6 (新) │ 虚拟分片320-383 (原256-383的后半部分)✓││
│ │ d_order_7 (新) │ 虚拟分片448-511 (原384-511的后半部分)✓││
│ └──────────────────┴──────────────────────────────────────────┘│
│ │
│ (damai_order_1库同理:虚拟分片512-1023) │
│ │
│ 总结: │
│ - 扩容前:2库×4表 │
│ - 扩容后:2库×8表 │
│ - 每类表:从4张扩展到8张,每张原表拆分为2张 │
│ - 虚拟分片映射:每个物理分片从128个虚拟分片减少到64个 │
│ - 停机时间:0(在线迁移) │
│ - 回滚能力:✓(修改路由表即可秒级回滚) │
└──────────────────────────────────────────────────────────────────┘

1.1 扩容步骤说明

步骤1:创建新物理表

-- 在现有库中创建新表(每个库每类表从4张扩展到8张)

-- ==================== damai_order_0 库 ====================
USE damai_order_0;
-- 1. 订单表(d_order)
DROP TABLE IF EXISTS `d_order_4`;
CREATE TABLE damai_order_0.d_order_4 LIKE damai_order_0.d_order_0;
DROP TABLE IF EXISTS `d_order_5`;
CREATE TABLE damai_order_0.d_order_5 LIKE damai_order_0.d_order_0;
DROP TABLE IF EXISTS `d_order_6`;
CREATE TABLE damai_order_0.d_order_6 LIKE damai_order_0.d_order_0;
DROP TABLE IF EXISTS `d_order_7`;
CREATE TABLE damai_order_0.d_order_7 LIKE damai_order_0.d_order_0;

-- ==================== damai_order_1 库 ====================
USE damai_order_1;
-- 1. 订单表(d_order)
DROP TABLE IF EXISTS `d_order_4`;
CREATE TABLE damai_order_1.d_order_4 LIKE damai_order_1.d_order_0;
DROP TABLE IF EXISTS `d_order_5`;
CREATE TABLE damai_order_1.d_order_5 LIKE damai_order_1.d_order_0;
DROP TABLE IF EXISTS `d_order_6`;
CREATE TABLE damai_order_1.d_order_6 LIKE damai_order_1.d_order_0;
DROP TABLE IF EXISTS `d_order_7`;
CREATE TABLE damai_order_1.d_order_7 LIKE damai_order_1.d_order_0;

-- 验证表结构
SHOW CREATE TABLE damai_order_0.d_order_4;

步骤2:迁移数据