基于 DMS 进行 DDL 同步的测试与分析
文章目录
- 一、测试场景:启用 DMS DDL 同步
- 1. 测试用例:直接在源数据库进行 DDL 变更
- 2. 测试用例:关停迁移任务→在源数据库进行 DDL 操作→恢复任务
- 3. 测试用例:停止迁移任务→在源和目标数据库同时进行 DDL 操作→恢复任务
- 二、测试场景: 关闭 DMS DDL 同步
- 测试用例:停止迁移任务→在源和目标数据库同时进行 DDL 操作→恢复任务
- 三、总结&综述
在当前云化快速发展的时代下,数据迁移和复制已经成为企业日常业务运维中重要的一环。其中,亚马逊云科技 数据库迁移服务(Amazon Database Migration Service,简称 DMS)作为一款高度可用、灵活的数据库迁移方案,帮助众多企业快速、安全地完成数据的异构迁移任务。Amazon DMS 支持不同数据库引擎间的迁移,例如 Oracle、SQL Server、MySQL、PostgreSQL,以及 Amazon Aurora 等多种数据库的相互复制和迁移,极大地简化了传统数据库迁移流程。
亚马逊云科技新推出的 Free Tier 2.0 是为了帮助开发者/企业用户 更低成本、更轻松地上手云服务。
免费计划 vs 付费计划
怎么理解这两种计划:账户注册时需选择免费或者付费计划。
免费计划:为新手/团队提供“零花费试用”的安全环境,最长 6 个月或用完抵扣金(以先到为准),除非主动切到付费计划,否则不产生费用。
付费计划:面向正式使用与扩展,可访问 150+ 亚马逊云科技 服务,系统会先用你的抵扣金抵扣符合条件的费用,超出部分按需计费。
除了数据库迁移场景,Amazon DMS 也被广泛用于数据库之间的持续复制,比如多个数据库的数据汇总,如下图所示。相比于使用 RDS 数据库的只读副本,Amazon DMS 可以将多个 RDS 数据库实例的不同数据表,汇总到同一个 RDS 数据库实例,提升资源的利用率。
但在实际生产环境中,数据库结构的变化,如新增数据表、字段修改、索引维护等操作(统称为 DDL 操作),都是不可避免的。
所以,源端业务系统的升级所引起的数据库 Schema 变更带来了挑战,困扰了许多用户。Amazon DMS 提供了高效的 DDL 同步特性,自动捕获并复制源数据库的 DDL 更改到目标数据库。例如常见的新增表、字段修改等操作,DMS 均可实时识别并处理这些变化。但就如何使用 DMS 的能力特性方面,客户也可能遇到以下疑问:
- 针对特定数据库,有哪些 DDL 不支持自动同步?
- 进行 DDL 变更时,要不要停止 DMS 任务?
- 若停止了 DMS 任务,做完了 DDL 变更,是恢复任务还重启任务?
- 什么场景下需要手动在源与目标进行 DDL 操作?
本文将以 RDS MySQL 为例,验证 Amazon DMS 在 DDL 同步方面的能力,并探索其功能边界与限制。如下图所示,罗列了本文将验证的场景。
一、测试场景:启用 DMS DDL 同步
在本测试场景中,先启用 DMS DDL 同步特性后,再进行各用例的测试。相关设置如下所示。
源与目标数据库引擎:RDS MySQL 8.0.40
DMS 复制实例版本:3.5.3
DMS 迁移任务的目标表模式:Truncate
启用 DDL 同步,需要在 DMS 迁移任务中进行如下配置:
"ChangeProcessingDdlHandlingPolicy": {
"HandleSourceTableDropped": true,
"HandleSourceTableTruncated": true,
"HandleSourceTableAltered": true
},
1. 测试用例:直接在源数据库进行 DDL 变更
本测试用例中,将在迁移任务运行的状态下,直接在源端进行 DDL 操作。测试脚本如下所示:
-- 启动DMS迁移任务前:在源与目标同步进行初始化
DROP TABLE IF EXISTS testtb;
CREATE TABLE IF NOT EXISTS testtb (id INT PRIMARY KEY ,name VARCHAR(50) NOT NULL
);
insert into testtb(id, name) values (1, 'test1');
insert into testtb(id, name) values (2, 'test2');
insert into testtb(id, name) values (3, 'test3');-- 启动DMS迁移任务后: 末尾添加字段
ALTER TABLE testtb ADD COLUMN `desc` VARCHAR(255);-- 启动DMS迁移任务后: 修改字段名
ALTER TABLE testtb CHANGE COLUMN name namestr VARCHAR(50) NOT NULL;
insert into testtb(id, namestr, `desc`) values (4, 'test4', 'test4 desc');-- 启动DMS迁移任务后: 修改字段类型
ALTER TABLE testtb MODIFY COLUMN namestr VARCHAR(100);-- 启动DMS迁移任务后: 删除字段
ALTER TABLE testtb DROP COLUMN `desc`;-- 启动DMS迁移任务后: truncate表
TRUNCATE TABLE testtb;-- 启动DMS迁移任务后: 新增索引
ALTER TABLE testtb ADD INDEX idx_name (namestr);
SHOW INDEXES FROM testtb;-- 启动DMS迁移任务后: 在中间添加字段
ALTER TABLE testtb ADD COLUMN `desc2` VARCHAR(255) AFTER `id`;-- 启动DMS迁移任务后: 重命名表
ALTER TABLE testtb RENAME TO testtb2;-- 启动DMS迁移任务后: 新增表
CREATE TABLE IF NOT EXISTS testtb3 (id INT PRIMARY KEY ,name VARCHAR(50) NOT NULL
);
insert into testtb3(id, name) values (5, 'test1');
insert into testtb3(id, name) values (6, 'test2');
insert into testtb3(id, name) values (7, 'test3');-- 启动DMS迁移任务后: 删除表
drop table testtb3;
测试结果如下:
2. 测试用例:关停迁移任务→在源数据库进行 DDL 操作→恢复任务
本用例中做了两次测试,第一次做全用例的测试,第二次剔除失败的 DDL 操作后,再进行测试。
第一次测试
本测试用例中,将在迁移任务关闭的状态下,在源端数据库进行 DDL 变更,然后再恢复 DMS 任务。测试脚本如下所示:
-- 启动DMS迁移任务前:在源与目标同步进行初始化
DROP TABLE IF EXISTS testtb;
CREATE TABLE IF NOT EXISTS testtb (id INT PRIMARY KEY ,name VARCHAR(50) NOT NULL
);
insert into testtb(id, name) values (1, 'test1');
insert into testtb(id, name) values (2, 'test2');
insert into testtb(id, name) values (3, 'test3');---------以下 SQL 在启动DMS迁移任务->再停止任务后,仅在源数据库执行----------------
-- 末尾添加字段
ALTER TABLE testtb ADD COLUMN `desc` VARCHAR(255);-- 修改字段名
ALTER TABLE testtb CHANGE COLUMN name namestr VARCHAR(50) NOT NULL;
insert into testtb(id, namestr, `desc`) values (4, 'test4', 'test4 desc');-- 修改字段类型
ALTER TABLE testtb MODIFY COLUMN namestr VARCHAR(100);-- 删除字段
ALTER TABLE testtb DROP COLUMN `desc`;-- truncate表
TRUNCATE TABLE testtb;-- 新增索引
ALTER TABLE testtb ADD INDEX idx_name (namestr);
SHOW INDEXES FROM testtb;-- 在中间添加字段
ALTER TABLE testtb ADD COLUMN `desc2` VARCHAR(255) AFTER `id`;-- 启动DMS迁移任务后: 重命名表
ALTER TABLE testtb RENAME TO testtb2;-- 新增表
CREATE TABLE IF NOT EXISTS testtb3 (id INT PRIMARY KEY ,name VARCHAR(50) NOT NULL
);
insert into testtb3(id, name) values (5, 'test1');
insert into testtb3(id, name) values (6, 'test2');
insert into testtb3(id, name) values (7, 'test3');-- 删除表
drop table testtb3;
---------------------最后再恢复 DMS 任务-------------------------------------------
测试结果:报错,详情如下所示:
第二次测试
分析上述日志,从日志分析,提示找不到 testtb,怀疑与 DDL 中的表重命名与字段重命名有关。参考测试用例 1 中的结果,在上述测试脚本的基础上,去除脚本中表重命,字段重命名,新增中间字段,新增索引后,重新进行测试。测试脚本如下所示:
-- 启动DMS迁移任务前:在源与目标同步进行初始化
DROP TABLE IF EXISTS testtb;
CREATE TABLE IF NOT EXISTS testtb (id INT PRIMARY KEY ,name VARCHAR(50) NOT NULL
);
insert into testtb(id, name) values (1, 'test1');
insert into testtb(id, name) values (2, 'test2');
insert into testtb(id, name) values (3, 'test3');---------以下 SQL 在启动DMS迁移任务->再停止任务后,仅在源数据库执行----------------
-- 末尾添加字段
ALTER TABLE testtb ADD COLUMN `desc` VARCHAR(255);-- 修改字段类型
ALTER TABLE testtb MODIFY COLUMN name VARCHAR(100);-- 删除字段
ALTER TABLE testtb DROP COLUMN `desc`;-- truncate表
TRUNCATE TABLE testtb;-- 新增表
CREATE TABLE IF NOT EXISTS testtb3 (id INT PRIMARY KEY ,name VARCHAR(50) NOT NULL
);
insert into testtb3(id, name) values (5, 'test1');
insert into testtb3(id, name) values (6, 'test2');
insert into testtb3(id, name) values (7, 'test3');-- 删除表
drop table testtb3;
---------------------最后再恢复 DMS 任务-------------------------------------------
测试结果:通过。 恢复 DMS 任务后,所有状态正常,后续的数据复制也正常。然后又分别针对重命名表、重命名字段、在中间插入字段,单独进行测试(停止任务→单独执行→恢复任务)。
- 重命名表:通过,但在目标数据库中是按新命名新建表、并未删除原有表
- 重命名字段:通过
- 在中间插入字段:不通过
3. 测试用例:停止迁移任务→在源和目标数据库同时进行 DDL 操作→恢复任务
本测试用例中,将在迁移任务关闭的状态下,同时在源端和目标端数据库进行 DDL 变更。结合前面的测试结论,我们剔除了一些确定不支持的 DDL,如字段重命名,表重命名,测试脚本如下所示:
-- 启动DMS迁移任务前:在源与目标同步进行初始化
DROP TABLE IF EXISTS testtb;
CREATE TABLE IF NOT EXISTS testtb (id INT PRIMARY KEY ,name VARCHAR(50) NOT NULL
);
insert into testtb(id, name) values (1, 'test1');
insert into testtb(id, name) values (2, 'test2');
insert into testtb(id, name) values (3, 'test3');---------以下 SQL 在启动DMS迁移任务->再停止任务后,在源和目标数据库同步执行----------------
-- 末尾添加字段
ALTER TABLE testtb ADD COLUMN `desc` VARCHAR(255);-- 修改字段类型
ALTER TABLE testtb MODIFY COLUMN name VARCHAR(100);-- 删除字段
ALTER TABLE testtb DROP COLUMN `name`;-- 添加索引
ALTER TABLE testtb ADD INDEX idx_name (desc);
SHOW INDEXES FROM testtb;-- truncate表
TRUNCATE TABLE testtb;-- 新增表
CREATE TABLE IF NOT EXISTS testtb3 (id INT PRIMARY KEY ,name VARCHAR(50) NOT NULL
);
insert into testtb3(id, name) values (5, 'test1');
insert into testtb3(id, name) values (6, 'test2');
insert into testtb3(id, name) values (7, 'test3');-- 删除表
drop table testtb3;---------------------最后再恢复 DMS 任务-------------------------------------------
测试结果:报错。并且根据日志提示,在测试脚本中剔除了删除字段的 SQL 后再次测试,仍然报错。
二、测试场景: 关闭 DMS DDL 同步
在本测试场景中,先关闭 DMS DDL 同步特性后,再进行各用例的测试。相关设置如下所示。
源与目标数据库引擎:RDS MySQL 8.0.40
DMS 复制实例版本:3.5.3
DMS 迁移任务的目标表模式:Truncate
关闭 DDL 同步,需要在 DMS 迁移任务中进行如下配置:
"ChangeProcessingDdlHandlingPolicy": {
"HandleSourceTableDropped": false,
"HandleSourceTableTruncated": false,
"HandleSourceTableAltered":false
},
测试用例:停止迁移任务→在源和目标数据库同时进行 DDL 操作→恢复任务
本用例中做了两次测试,第一次做全用例的测试,第二次剔除失败的 DDL 操作后,再进行测试。
第一次测试
本测试用例中,将在迁移任务关闭的状态下,同时在源端和目标端数据库进行 DDL 变更。测试脚本如下所示:
-- 启动DMS迁移任务前:在源与目标同步进行初始化
DROP TABLE IF EXISTS testtb;
CREATE TABLE IF NOT EXISTS testtb (id INT PRIMARY KEY ,name VARCHAR(50) NOT NULL
);
insert into testtb(id, name) values (1, 'test1');
insert into testtb(id, name) values (2, 'test2');
insert into testtb(id, name) values (3, 'test3');---------以下 SQL 在启动DMS迁移任务->再停止任务后,在源和目标数据库同步执行----------------
-- 末尾添加字段
ALTER TABLE testtb ADD COLUMN `desc` VARCHAR(255);-- 修改字段名
ALTER TABLE testtb CHANGE COLUMN name namestr VARCHAR(50) NOT NULL;
insert into testtb(id, namestr, `desc`) values (4, 'test4', 'test4 desc');-- 修改字段类型
ALTER TABLE testtb MODIFY COLUMN namestr VARCHAR(100);-- 删除字段
ALTER TABLE testtb DROP COLUMN `desc`;-- truncate表
TRUNCATE TABLE testtb;-- 新增索引
ALTER TABLE testtb ADD INDEX idx_name (namestr);
SHOW INDEXES FROM testtb;-- 在中间添加字段
ALTER TABLE testtb ADD COLUMN `desc2` VARCHAR(255) AFTER `id`;-- 启动DMS迁移任务后: 重命名表
ALTER TABLE testtb RENAME TO testtb2;-- 新增表
CREATE TABLE IF NOT EXISTS testtb3 (id INT PRIMARY KEY ,name VARCHAR(50) NOT NULL
);
insert into testtb3(id, name) values (5, 'test1');
insert into testtb3(id, name) values (6, 'test2');
insert into testtb3(id, name) values (7, 'test3');-- 删除表
drop table testtb3;---------------------最后再恢复 DMS 任务-------------------------------------------
测试结果:报错,如下图所示。
第二次测试
从日志分析,提示找不到 testtb,怀疑与 DDL 中的表重命名与字段重命名有关。参考测试场景一的测试结果,在上述测试脚本的基础上,去除脚本中表重命名与字段重命名 SQL 后,重新进行测试。
-- 启动DMS迁移任务前:在源与目标同步进行初始化
DROP TABLE IF EXISTS testtb;
CREATE TABLE IF NOT EXISTS testtb (id INT PRIMARY KEY ,name VARCHAR(50) NOT NULL
);
insert into testtb(id, name) values (1, 'test1');
insert into testtb(id, name) values (2, 'test2');
insert into testtb(id, name) values (3, 'test3');---------以下 SQL 在启动DMS迁移任务->再停止任务后,在源和目标数据库同步执行----------------
-- 末尾添加字段
ALTER TABLE testtb ADD COLUMN `desc` VARCHAR(255);-- 修改字段类型
ALTER TABLE testtb MODIFY COLUMN namestr VARCHAR(100);-- 删除字段
ALTER TABLE testtb DROP COLUMN `desc`;-- truncate表
TRUNCATE TABLE testtb;-- 新增索引
ALTER TABLE testtb ADD INDEX idx_name (namestr);
SHOW INDEXES FROM testtb;-- 在中间添加字段
ALTER TABLE testtb ADD COLUMN `desc2` VARCHAR(255) AFTER `id`;-- 新增表
CREATE TABLE IF NOT EXISTS testtb3 (id INT PRIMARY KEY ,name VARCHAR(50) NOT NULL
);
insert into testtb3(id, name) values (5, 'test1');
insert into testtb3(id, name) values (6, 'test2');
insert into testtb3(id, name) values (7, 'test3');-- 删除表
drop table testtb3;---------------------最后再恢复 DMS 任务-------------------------------------------
测试结果:通过。恢复 DMS 任务后,所有状态正常,后续的数据复制也正常。然后又分别针对重命名表、重命名字段、在中间插入字段,单独进行测试(停止任务→单独执行→恢复任务)。
- 重命名表:通过
- 重命名字段:通过
三、总结&综述
在 Amazon DMS 开启 DDL 的情况下,测试结果如下所示。
在Amazon DMS 关闭 DDL 同步的情况下,测试结果如下所示。
基于以上的测试结果说明,在使用 Amazon DMS 进行 DMS 同步时,建议要么开启 DDL 同步特性、并在任务运行状态下在源端做 DDL 操作,要么在关闭 DDL 同步特性、并在任务停止状态下手动在源与目标端进行 DDL 操作。为了更进一步的说明细节,本文给出以下的决策图。至于决策图中未提及的索引,经过测试无法使用 DDL 同步特性进行同步,但可以直接手动在源和目标进行新增、修改和删除。
综上所述,本文以 MySQL 8.0.40为例,测试了 DMS 对于 DDL 变更的支持,并基于测试结果,给出了实践中的决策建议。
但考虑 DMS 在将 DDL 语句应用于特定目标引擎时,处理方式各不相同。所以,在使用 DMS 同步其他数据库引擎时,需要结合 亚马逊云科技 官方文档与实际测试结果来决策相关配置。
以上就是本文的全部内容啦。最后提醒一下各位工友,如果后续不再使用相关服务,别忘了在控制台关闭,避免超出免费额度产生费用~