暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL 迁移至 OceanBase 的反向增量及回退方案

199

作者:郑增权,爱可生 DBA 团队成员,OceanBase 和 MySQL 数据库技术爱好者。

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文约 2500 字,预计阅读需要 8 分钟。


1. 背景

将 MySQL 迁移至 OceanBase 之后,除了正向增量数据之外,有时需要做反向增量以确保 OceanBase 端新产生的数据实时回写到 MySQL 端,以便在业务测试不充分时可以及时回退到 MySQL 端。

正向切换的步骤包含 “请自行在在源端禁用触发器和外键等对象”,此操作的作用在开启反向同步的情况下是为了避免往 OceanBase 端写入的数据在 MySQL 由于触发器和外键导致数据二次更新,造成数据混乱。

本文将梳理讲解 MySQL 迁移至 OceanBase 时,进行 反向增量 的主要步骤及注意事项。

2. 术语解释

正文开始前,我们先解释两个术语。

正向切换

在 MySQL 迁移至 OceanBase 的数据迁移链路中,停止 MySQL 端业务写入及补建非表对象,业务侧将连接 OceanBase 并启动业务,这个过程称为正向切换。

反向增量

在业务流量由 MySQL 切换到 OceanBase 之后,将 OceanBase 端新产生的数据回写至 MySQL 端,这个操作叫做反向增量。

3. 方案概述

在具体操作前,需要梳理明确 反向增量方案 的前置约束、数据迁移流程及回退预案。


3.1 反向增量的前置约束

在进行反向增量操作之前,需要注意以下几点前置约束:

① 不支持反向增量的情况

  • 多表汇聚
  • Schema 多到一映射

② 禁用 MySQL 端触发器

由于 MySQL 无法直接禁用触发器,需要备份触发器。在正向切换之后,MySQL 端删除本次迁移涉及的触发器。

③ 禁用 MySQL 端的外键

由于 MySQL 无法直接禁用外键,需要准备好删除外键和创建外键的 SQL 语句。在正向切换之后,MySQL 端删除本次迁移涉及的外键。

注意:请在测试环境先验证 SQL 语句正确性。

④ 开启日志归档以便读取增量数据

  • MySQL 端开启 Binlog 服务
  • OceanBase 端开启日志归档服务

⑤ 同步的 DDL 范围限制

正向或反向增量同步支持的 DDL 语句范围都有一定的约束(具体可查看官方文档),且持续的时间一般不宜过长,同时也需避免因为“不合规”的 DDL 语句导致同步链路中断。

3.2 数据迁移(一般)流程

  1. 锁定 OceanBase 端业务用户
  2. MySQL 迁移至 OceanBase 的数据链路提前运行到增量同步阶段
  3. 正式切换当天停止业务
  4. 锁定 MySQL 端业务用户并 kill 掉相关连接
  5. 等待数据追平
  6. 执行全量数据校验
  7. 执行正向切换

此处需确保 MySQL 到 OceanBase 的增量组件已经完全停止,再做后续的删除触发器和外键操作,否则可能导致 OceanBase 端的触发器和外键也被删除。

  1. OceanBase 端导入非表对象
  2. 备份并删除 MySQL 端触发器
  3. 备份并删除 MySQL 端外键
  4. 启动反向增量
  5. 解锁 OceanBase 端业务用户
  6. 业务侧连接至 OceanBase 数据库并启动业务

3.3 回退预案(切回 MySQL 运行业务)

  1. 停止业务流量写入
  2. 锁定 OceanBase 端业务用户并 kill 掉相关连接
  3. 等待数据追平
  4. 停止反向增量
  5. 新增数据校验链路进行两端数据校验确认数据一致
  6. MySQL 端创建触发器
  7. MySQL 端创建外键
  8. 解锁 MySQL 端业务用户
  9. 业务侧连接至 MySQL 数据库并启动业务

注意:此处我们省去结构迁移和全量迁移等步骤,重点关注正向切换、启动反向增量、停止反向增量及回退至 MySQL。

4. OMS 执行正向切换

正向切换的全过程包括 Setp 1 到 Step 7。

Setp 1
Setp 2 - 4
Setp 5 - 7

注意:一定要确认 Step 6(停止正向同步,停止源端到目标端的 Incr-Sync)已经完成,再做后续步骤。

避免后续 MySQL 端删除触发器和外键的行为也同步到 OceanBase 端。

5. 导入非表对象

  1. 基于 DBCat 针对存储过程、函数、触发器等非表对象进行转换,由 MySQL 转为 OceanBase MySQL 兼容的 DDL 语法。
  2. 在 OceanBase MySQL 端进行非表对象(如触发器)创建。

6. 针对触发器和外键的处理

6.1 触发器

  1. 使用 mysqldump 导出触发器。
mysqldump -h10.186.65.14  -P3306 -uoms_mysql -p'xxxxxxxxxx'  --single-transaction --set-gtid-purged=OFF --no-data --no-create-info --triggers --databases company_db > tmp/company_db_triggers.sql

注意:以上语句对于 MyISAM 存储引擎的表可能产生短暂锁表,请避免在业务高峰期执行!

  1. MySQL 端查询当前存在的触发器
MySQL [company_db]> SELECT TRIGGER_SCHEMA,TRIGGER_NAME FROM information_schema.triggers WHERE trigger_schema = 'company_db';
+----------------+----------------------+
| TRIGGER_SCHEMA | TRIGGER_NAME         |
+----------------+----------------------+
| company_db     | set_hire_date        |
| company_db     | check_project_emp_id |
+----------------+----------------------+
2 rows in set (0.01 sec)

  1. MySQL 端删除触发器
-- 动态生成删除触发器的 SQL 语句
SELECT CONCAT('DROP TRIGGER IF EXISTS ', trigger_name, ';') AS drop_statement
FROM information_schema.triggers
WHERE trigger_schema = 'company_db'
INTO OUTFILE '/tmp/drop_triggers.sql';

-- 记录删除触发器的语句(注意不要删除到非本次迁移库的触发器!)
[root@10-186-65-14 tmp]# cat tmp/drop_triggers.sql
DROP TRIGGER IF EXISTS set_hire_date;
DROP TRIGGER IF EXISTS check_project_emp_id;

-- 执行删除触发器
MySQL [company_db]> DROP TRIGGER IF EXISTS set_hire_date;
Query OK, 0 rows affected (0.00 sec)

MySQL [company_db]> DROP TRIGGER IF EXISTS check_project_emp_id;
Query OK, 0 rows affected (0.01 sec)

-- 确认对应库的触发器数量为 0
MySQL [company_db]> SELECT COUNT(*)  FROM information_schema.triggers WHERE trigger_schema = 'company_db';
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

6.2 外键

  1. MySQL 端生成删除外键的 SQL 命令
USE company_db;

-- 生成删除外键的 SQL 语句
SELECT CONCAT('ALTER TABLE ', table_name, ' DROP FOREIGN KEY ', constraint_name, ';') AS drop_statement
FROM information_schema.table_constraints
WHERE constraint_type = 'FOREIGN KEY'AND table_schema = 'company_db'
INTO OUTFILE'/tmp/drop_foreign_keys.sql';

-- 查看生成的删除外键的 SQL 语句
[root@10-186-65-14 tmp]# cat drop_foreign_keys.sql 
ALTER TABLE employees DROP FOREIGN KEY employees_ibfk_1;
ALTER TABLE projects DROP FOREIGN KEY projects_ibfk_1;

  1. MySQL 端生成创建外键的 SQL 命令
-- 生成创建外键的 SQL 语句(预先准备,无需执行,仅在回退时需要创建)
SELECT CONCAT('ALTER TABLE ', tc.table_name, ' ADD CONSTRAINT ', tc.constraint_name, 
              ' FOREIGN KEY (', kcu.column_name, ') REFERENCES ', kcu.referenced_table_name, 
              ' (', kcu.referenced_column_name, ');') AS create_statement
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu 
ON tc.constraint_name = kcu.constraint_name 
AND tc.table_schema = kcu.table_schema
WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_schema = 'company_db'
INTO OUTFILE '/tmp/create_foreign_keys.sql';


-- 查看生成的创建外键的 SQL 语句
[root@10-186-65-14 tmp]# cat create_foreign_keys.sql 
ALTER TABLE employees ADD CONSTRAINT employees_ibfk_1 FOREIGN KEY (dept_id) REFERENCES departments (dept_id);
ALTER TABLE projects ADD CONSTRAINT projects_ibfk_1 FOREIGN KEY (emp_id) REFERENCES employees (emp_id);

  1. MySQL 端执行删除外键
MySQL [company_db]> ALTER TABLE projects DROP FOREIGN KEY projects_ibfk_1;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0
MySQL [company_db]> ALTER TABLE employees DROP FOREIGN KEY employees_ibfk_1;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

6.3 OMS 标记非表对象导入完成

7. 启动反向增量

7.1 OMS 点击“确认启动反向增量”

7.2 验证反向增量和外键约束的有效性

在 OceanBase 端针对涉及外键的表执行插入数据:

  • 确认数据可以同步至 MySQL 端
  • 在 OceanBase 端插入违反外键约束的数据确认外键的有效性
--插入数据
obclient [company_db]> INSERT INTO departments (dept_name, location) VALUES ('Training', 'Houston');
Query OK, 1 row affected (0.021 sec)

obclient [company_db]> INSERT INTO employees (first_name, last_name, dept_id, hire_date) VALUES ('Alice', 'Green', 11, '2025-09-05');
Query OK, 1 row affected (0.023 sec)

obclient [company_db]> INSERT INTO projects (project_name, emp_id, start_date) VALUES ('Training Portal', 11, '2025-10-01');
Query OK, 1 row affected (0.036 sec)

-- MySQL 端确认数据已经同步
MySQL [company_db]> select * from projects;
+------------+------------------+--------+------------+
| project_id | project_name     | emp_id | start_date |
+------------+------------------+--------+------------+
--中间输出省略
|         11 | Training Portal  |     11 | 2025-10-01 |
+------------+------------------+--------+------------+
11 rows in set (0.00 sec)


-- 插入违反外键约束的数据
obclient [company_db]> INSERT INTO employees (first_name, last_name, dept_id, hire_date) VALUES ('Bob', 'White', 999, '2025-09-05');
ERROR 1452 (23000): Cannot add or update a childrow: a foreign key constraint fails
obclient [company_db]> INSERT INTO projects (project_name, emp_id, start_date) VALUES ('Invalid Project', 999, '2025-10-01');
ERROR 1452 (23000): Cannot add or update a childrow: a foreign key constraint fails

8. 停止反向增量及回退至 MySQL

  1. 业务侧停止往 OceanBase 端写入数据
  2. 锁定 OceanBase 端业务用户并 kill 掉相关连接
  3. 等待数据追平
  4. 暂停反向增量
  1. 新增数据校验链路进行两端数据校验

注意:确认 MySQL 和 OceanBase 两端数据一致再进行后续操作。

9. MySQL 端创建触发器和外键

9.1 创建外键

--导入外键
MySQL [company_db]> ALTER TABLE employees ADD CONSTRAINT employees_ibfk_1 FOREIGN KEY (dept_id) REFERENCES departments (dept_id);
Query OK, 11 rows affected (0.02 sec)
Records: 11  Duplicates: 0  Warnings: 0

MySQL [company_db]> ALTER TABLE projects ADD CONSTRAINT projects_ibfk_1 FOREIGN KEY (emp_id) REFERENCES employees (emp_id);
Query OK, 11 rows affected (0.03 sec)
Records: 11  Duplicates: 0  Warnings: 0

9.2 创建触发器

--导入触发器
mysql -h10.186.65.14 -P3306 -uoms_mysql -p'$pwd' company_db < company_db_triggers.sql

--确认触发器导入成功
MySQL [company_db]> SELECT TRIGGER_SCHEMA,TRIGGER_NAME FROM information_schema.triggers WHERE trigger_schema = 'company_db';
+----------------+----------------------+
| TRIGGER_SCHEMA | TRIGGER_NAME         |
+----------------+----------------------+
| company_db     | set_hire_date        |
| company_db     | check_project_emp_id |
+----------------+----------------------+
2 rows in set (0.00 sec)

10. 解锁 MySQL 端业务用户

业务侧连接 MySQL 并启动业务进行验证,将流量回切至 MySQL。

11. 参考资料

《查看数据迁移任务的详情》: https://www.oceanbase.com/docs/enterprise-oms-doc-cn-1000000003095422


本文关键字:#OceanBase #数据迁移 #反向迁移





2000 倍性能提升!Semi Join 改写全过程分析
3.X vs 4.X:OceanBase 手动收集统计信息的天壤之别!
一个案例掌握 OMS 校验方式及适用场景
OBLogProxy 在 Binlog 模式下的故障案例解析



✨ Github:https://github.com/actiontech/sqle

📚 文档:https://actiontech.github.io/sqle-docs/

💻 官网:https://opensource.actionsky.com/sqle/

👥 微信群:请添加小助手加入 ActionOpenSource

🔗 商业支持:https://www.actionsky.com/sqle


文章转载自爱可生开源社区,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论