一、为什么需要数据迁移

假设你开了一家连锁超市,原先用纸质账本记录库存(比如MySQL),现在要升级成智能ERP系统(比如OceanBase)。旧账本里的数据不能丢,还要保证营业不受影响——这就是典型的数据迁移场景。

常见原因

  • 数据库性能遇到瓶颈(比如单表超过500万行查询变慢)
  • 业务需要跨数据库联合分析(如MySQL和OceanBase混合查询)
  • 国产化替代等政策要求

真实案例
某电商平台将促销活动的秒杀数据从MySQL迁移到OceanBase,QPS(每秒查询量)从2000提升到15000,同时节省了60%的服务器成本。

二、迁移前的准备工作

1. 环境检查清单

就像搬家前要量好新房子尺寸,你需要确认:

-- OceanBase版本检查(示例)  
SELECT @@version;  
-- 预期输出:OceanBase 4.x.x  

2. 数据兼容性比对

重点检查这些字段类型差异:

MySQL类型 OceanBase对应类型
TEXT CLOB
DATETIME(6) TIMESTAMP(6)

特殊处理示例

-- 处理自增主键差异  
-- MySQL原表  
CREATE TABLE orders (  
  id INT AUTO_INCREMENT PRIMARY KEY  
);  

-- OceanBase适配方案  
CREATE TABLE orders (  
  id NUMBER GENERATED BY DEFAULT AS IDENTITY  
);  
-- 注释:OceanBase使用IDENTITY代替AUTO_INCREMENT  

三、四种迁移方案实战

1. 停机迁移(适合小型系统)

操作流程

  1. 停掉老系统
  2. 用mysqldump导出数据
  3. 通过OBLoader导入
# 技术栈:OceanBase+MySQL  
# 步骤2导出命令示例  
mysqldump -uroot -p123456 --single-transaction mydb > backup.sql  

# 步骤3导入命令(注意字符集转换)  
obloader -h127.0.0.1 -P2881 -uroot -p123456 --sys-password=123456 \  
  -c utf8mb4 -t mydb -f backup.sql  

2. 双写迁移(零停机方案)

架构图逻辑

[应用] → [MySQL]  
      ↘ [OceanBase]  

代码示例

// 技术栈:Java Spring Boot  
@Service  
public class OrderService {  
  @Transactional  
  public void createOrder(Order order) {  
    // 双写逻辑  
    mysqlMapper.insert(order);  // 写MySQL  
    oceanbaseMapper.insert(order); // 写OceanBase  
    
    // 注释:建议增加异步校验机制核对两边数据  
  }  
}  

3. CDC增量同步(最推荐方案)

使用Canal监听MySQL的binlog:

# canal.deployer配置示例  
canal.instance.mysql.slaveId = 1234  
canal.instance.filter.regex = mydb\\..*  
canal.mq.topic = ob_migration  

4. 中间件方案(如ShardingSphere)

-- 创建逻辑表  
CREATE SHARDING TABLE t_order (  
  id BIGINT,  
  user_id INT  
) ENGINE=OceanBase;  

-- 注释:实际数据可分布在MySQL和OceanBase多个节点  

四、避坑指南

1. 时间字段陷阱

MySQL的TIMESTAMP会受时区影响,建议统一用DATETIME

-- 错误示例  
CREATE TABLE problem (  
  create_time TIMESTAMP  
);  

-- 正确方案  
CREATE TABLE safe_table (  
  create_time DATETIME  
);  

2. 大事务处理

OceanBase默认事务限制为100MB,大表迁移需要分片:

# 技术栈:Python分片脚本  
def chunk_migrate(table, batch_size=1000):  
    max_id = get_max_id()  
    for i in range(0, max_id, batch_size):  
        data = query_mysql(f"SELECT * FROM {table} WHERE id BETWEEN {i} AND {i+batch_size-1}")  
        insert_oceanbase(data)  

3. 数据校验神器

使用CRC32快速比对数据一致性:

-- MySQL端计算校验值  
SELECT SUM(CRC32(CONCAT(id,name))) FROM users;  

-- OceanBase端比对  
SELECT SUM(CRC32(CONCAT(id,name))) FROM users;  

五、迁移后的必做事项

  1. 性能压测:用sysbench模拟真实流量

    sysbench oltp_read_write --db-driver=mysql \  
     --mysql-host=obproxy --mysql-port=2883 run  
    
  2. 监控指标:重点关注

    • 磁盘水位超过80%需要扩容
    • 内存使用率持续高于70%需优化
  3. 回滚方案

    • 保留旧数据库至少2周
    • 准备SQL回滚脚本(逆向操作)

六、技术选型建议

方案 适合场景 实施难度
停机迁移 小型系统、容忍停机 ★★☆☆☆
CDC同步 大型生产系统 ★★★★☆
双写 金融级一致性要求 ★★★★★

特别提醒:如果源库是Oracle,要特别注意CLOB字段的处理,建议先用DMS工具做一次结构分析。