阿里云 DTS 数据迁移:从预检查、全量增量到校验切换与退出
先别切流:目标库有数据不等于迁移成功
一家电商准备把运行多年的 MySQL 订单库迁入新的托管数据库。全量任务显示完成,目标库也能查到订单,团队便在低峰期把应用连接串改了过去。十几分钟后,客服发现一批刚付款的订单仍停留在“待支付”,库存却已经扣减。大家回到迁移控制台才发现:全量完成之后,增量链路曾因目标表缺少兼容索引而持续延迟;某个表的 DDL 失败后处于异常状态;切换前只比较了总行数,没有检查最近更新、失败对象和增量水位。
这类事故的危险之处在于,目标库不是空的,抽查也大概率正常。真正缺失的是一条证据链:全量基线取自哪个时刻,基线之后的变更从哪里开始采集,哪些对象复制成功,延迟是否在稳定下降,源目标差异是否已经消失,停止任务时最后一个已提交变更在哪里,以及回切时谁仍是唯一权威写入端。
阿里云 Data Transmission Service 的产品名是数据传输服务 DTS。它提供数据迁移、数据同步、数据订阅和数据校验等能力;这里出现的 DTS 不能与阿里云数据管理服务 DMS 混称。DMS 更偏向数据库开发、访问、变更和治理工作台,DTS 则在这次现场中承担数据移动与变更追赶。官方的 DTS 产品说明 将迁移过程描述为全量装载与增量同步的组合:全量搬运历史数据的同时采集源端日志,之后再把积压变更应用到目标端。
把托管服务看成四个运行对象
DTS 不需要在开发机安装一个常驻迁移进程。团队在控制台或 OpenAPI 创建任务实例,数据面由云服务运行,但数据库、网络、凭证和切换责任仍属于使用方。理解下面四个对象,比记住控制台按钮更重要。
端点是源库和目标库。端点不仅是主机名与端口,还包含接入方式、数据库类型、账号、TLS/网络策略和对象兼容边界。连接测试成功只证明 DTS 节点能建立数据库会话,不证明账号能读取日志、创建目标对象或应用 DDL。
任务实例保存迁移类型、对象映射、运行规格和状态。数据迁移通常面向一次性搬迁;需要长期保持两端变化时,应重新判断数据同步是否更合适,不能让“临时迁移任务”没有 owner 地永久运行。
迁移阶段通常包括结构迁移、全量数据迁移和增量数据迁移。官方 DTS 架构说明 指出,全量开始时增量读取器就会捕获源端变化,变更先被解析、转换并暂存,待全量完成后再持续应用到目标端。因此“全量完成”只是历史基线完成,并非切换信号。
校验任务比较源端和目标端的结构或数据。官方 数据校验说明 区分结构校验、全量数据校验和增量数据校验;增量校验面对的是发生过 DML 变化的记录,并会对疑似不一致再次核验,以减少迁移延迟造成的假阳性。校验是独立证据,不应被“任务正在运行”替代。
这个图里有两条并行水流:历史基线与迁移期间产生的日志。任一条断开,目标端都可能“看起来有数据”但不能接管业务。DTS 托管了采集、转换和应用进程,并没有替团队定义业务不变量、冻结写入窗口或回滚裁决规则。
先让网络和账号真正可用
迁移设计的第一张图应是网络路径,而不是对象列表。阿里云实例、自建 ECS 数据库、线下机房、其他云数据库、公网地址以及通过专线、VPN、智能接入网关或云企业网接入的数据库,需要选择与真实拓扑一致的接入方式。不要为了让连接测试变绿,临时把数据库端口向整个公网开放。
地域边界必须在买实例前核对,而不是等连接测试报错。官方 跨地域与跨境任务说明 将同地域、跨地域和跨境分开处理:跨地域数据迁移通常需要公网连通,源端接入方式不同还会改变究竟由哪一端提供公网地址;跨境链路还涉及单独的合规与权限条件。若数据库所在地域尚未被 DTS 直接支持,官方 DTS FAQ 给出的迁移兜底是选择受支持的 DTS 地域、以公网地址接入并放行该地域的 DTS 地址段,但数据同步不支持用这个公网办法绕过地域缺口。Database Gateway 也不能被当成生产专线:官方 Database Gateway 接入说明 将它定位为 POC 工具,并说明该方式下跨地域数据迁移不受支持。实施单因此要同时写明任务地域、两端地域、任务类型、接入方式、实际流量方向和跨境审批结论。
对于受防火墙或白名单保护的自建数据库,DTS 节点地址必须进入相应安全策略。官方 DTS 服务器地址白名单说明 强调:公网、专线、VPN、智能接入网关或云企业网接入可能需要手工维护地址段;集群型数据库的每个相关节点都要放行;容灾切换可能使用不同服务节点,遗漏地址段会让任务在故障转移后中断。任务退出后还应移除专用白名单,不能把 DTS 自动维护的规则借给其他服务使用。
网络排查按层次进行。DNS 解析失败时看不到数据库握手;路由或安全组不通通常表现为连接超时;端口可达但 TLS、账号或 host 授权错误,会出现握手或认证失败;连接测试通过而预检查失败,则更可能是日志参数、版本、权限或对象约束问题。记录每层证据,避免反复重置密码掩盖路由错误。
账号权限必须根据数据库类型和迁移阶段配置,而不是复制一个永久 DBA 账号。官方 迁移账号权限矩阵 会随源目标组合变化,创建任务前应按实际链路核对。以自建 MySQL 的增量迁移为例,当前矩阵要求源账号具有迁移对象上的 SELECT、SHOW VIEW,全局 REPLICATION CLIENT、REPLICATION SLAVE 和 CREATE;其中 CREATE 供 DTS 创建 dts 数据库并写入心跳数据。目标账号需要在目标库创建或写入对象的权限。RDS MySQL 等托管源使用另一套账号模型,不应照抄自建库授权;不同异构目标和 DDL 选择也会改变要求。
-- 合成实验账号,只允许从受控网段接入;生产授权按实际链路的官方矩阵收敛。
CREATE USER 'dts_reader'@'10.%' IDENTIFIED BY '<source-password>';
GRANT SELECT, SHOW VIEW ON shop_demo.* TO 'dts_reader'@'10.%';
GRANT REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO 'dts_reader'@'10.%';
GRANT CREATE ON *.* TO 'dts_reader'@'10.%';
CREATE USER 'dts_writer'@'10.%' IDENTIFIED BY '<target-password>';
GRANT ALL PRIVILEGES ON shop_demo.* TO 'dts_writer'@'10.%';
SHOW GRANTS FOR 'dts_reader'@'10.%';
SHOW GRANTS FOR 'dts_writer'@'10.%';这里故意把源读账号和目标写账号拆开。CREATE ON *.* 仍是全局能力,虽然没有赋予源业务库 DML 权限,也必须作为任务期临时权限治理。任务停止且不再依赖心跳后,先保存 SHOW GRANTS 证据,再执行 REVOKE CREATE ON *.* FROM 'dts_reader'@'10.%';;若账号不再复用,则直接删除账号,并确认专用 dts 库是否可按变更单清理。目标账号也不应能越过迁移库访问无关数据库。使用 KMS、凭证托管或控制台密文能力时,要明确谁能读取密文、谁只能引用它、轮换后任务如何重新建立连接。控制台截图、预检查详情、失败 SQL 和差异报告都可能包含库表名或数据样本,应进入受控工单或加密存储,不应贴进公共聊天。
创建任务时,每个字段都在改变风险
进入 DTS 控制台创建数据迁移任务时,先选择真实的源端、目标端和接入方式,再选择结构、全量和增量阶段。一次希望低停机切换的在线迁移通常同时选择三者。只选全量意味着全量读取开始后的新写入不会自动追平;只选增量则要求目标端已有可证明一致的基线与正确日志起点。
“DTS 支持 MySQL”仍然太粗。当前能力要按源部署形态、源版本、目标类型、任务类型、结构/全量/增量阶段、DDL、校验类型、地域和标准/Serverless 形态逐格确认。官方 迁移场景总表 只是入口,最终约束在对应源目标组合页面;控制台里能选到某种数据库,也不自动证明该组合支持增量、全部对象或当前地域。评审证据应保存对应组合页面和任务配置快照,不能只留产品总览链接。
迁移对象应从显式库表开始,不要一上来选择整个实例。系统库、审计库、临时表和高敏感表可能不应进入目标;通配式全选还会把不兼容对象和无 owner 数据带入任务。对象重命名、过滤和异构映射会改变目标数据语义,应放入评审并保存配置快照。
结构迁移需要逐类确认表、索引、视图、触发器、存储过程、函数、事件与账号是否受当前源目标组合支持。能够创建表不代表所有 DDL 都能持续复制。迁移期间业务仍可能发布 Schema 变更,若对应操作不受链路支持,任务可能在单个对象上失败或目标结构漂移。稳妥做法是在迁移窗口冻结非必要 DDL;确需变更时,先在同组合演练环境验证,再决定由 DTS 传播还是由受控数据库变更流程分别执行。
下面的 YAML 不是可直接提交给 DTS 的 API 请求,而是一份项目仓库中的迁移意图清单。它把容易藏在控制台里的决策带回代码评审,值使用合成数据和占位凭证引用。
migration_id: shop-demo-to-managed-mysql
service: aliyun-dts
source:
engine: mysql
database: shop_demo
access: private-network
credential_ref: secret://migration/dts-source
target:
engine: mysql
database: shop_demo
credential_ref: secret://migration/dts-target
phases: [schema, full-load, incremental]
objects:
include: [orders]
exclude: [debug_events, local_sessions]
cutover:
authority_before: source
write_freeze_required: true
validation: [schema, full-data, incremental, business-invariants]
rollback:
authority_during_observation: target
reverse_path_owner: data-platform-team实例规格会影响全量吞吐和增量追赶能力,但越大不等于越安全。源库可承受的扫描 IO、网络出口、目标写入能力、最大事务、热表更新率和迁移窗口共同决定容量。规格选择应基于基线压测与趋势,避免用一个固定延迟数字套所有业务。费用也不只来自任务实例:公网或跨网络流量、校验任务、日志与监控保留、源目标扩容以及任务忘记释放都会产生持续资源消耗。评审时记录计费项和 owner,不在文档里写死地区、套餐或金额。
预检查不是“点一下重试”
DTS 会在启动前检查源目标连通性、账号权限、日志设置、数据库版本和部分对象条件。官方 术语说明 对预检查的定义正是启动前验证这些运行条件;失败后应查看失败项、修复根因,再重新检查。预检查通过表示已知静态条件满足,不表示容量足够、所有增量 DDL 可用或业务切换一定安全。
把失败项按责任域分组更高效:
| 失败证据 | 优先判断 | 修复后如何证明 |
|---|---|---|
| 源库/目标库连接超时 | 路由、安全组、白名单、DNS、端口 | 连接测试成功且数据库审计出现 DTS 会话 |
| Access denied | 密码、host 限制、对象权限、复制权限 | SHOW GRANTS 与预检查权限项同时通过 |
| Binlog/WAL 配置失败 | 日志未开启、格式或保留不满足 | 数据库参数与日志位点可查询,预检查重跑通过 |
| 对象约束失败 | 无主键、重名、类型或 DDL 不兼容 | 修正对象或显式排除,保存差异决策 |
| 版本检查失败 | 源目标版本组合不受当前链路支持 | 在对应迁移场景文档确认组合后重新建模 |
官方 预检查失败排查 给出了连接凭证、地址白名单和防火墙等典型原因。不要为了通过检查永久授予全局权限,也不要在找不到原因时反复删除重建任务。保留失败项名称、错误码、发生对象、最近一次配置变更和修复动作,后续才能区分“同一错误重现”与“修复后出现下一层问题”。
正向实验:证明全量能够接上增量
下面是待执行实验设计,本次复审未创建云资源、未连接数据库,也未执行 SQL。真正演练时使用临时 DTS 任务和合成数据库:先在源库创建一张 orders 表并写入基线,把任务对象也只选择 shop_demo.orders,再启动结构、全量与增量迁移;全量进行期间提交一次更新和一次新增。命令在源库 localhost 上演示,实际 DTS 通过受控网络访问该数据库。
CREATE DATABASE IF NOT EXISTS shop_demo;
USE shop_demo;
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
status VARCHAR(32) NOT NULL,
version INT NOT NULL,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
);
INSERT INTO orders(id, status, version) VALUES
(1001, 'CREATED', 1),
(1002, 'PAID', 2);
-- DTS 全量阶段已经开始后再提交,验证增量接续。
UPDATE orders SET status = 'PAID', version = 2 WHERE id = 1001;
INSERT INTO orders(id, status, version) VALUES (1003, 'CREATED', 1);预期结果不是只看到三行。应同时收集四类证据:结构阶段中 orders 成功;全量对象完成且没有失败对象;增量延迟在源端停止写入后回落并稳定;目标端 1001 的状态与版本是 PAID/2,1003 存在。随后在 DTS 数据校验中运行适用于当前链路的结构、全量或增量校验,并用业务查询核对状态分布和版本单调性。
-- 在源库和目标库分别执行,记录结果与查询水位。
SELECT COUNT(*) AS row_count,
SUM(status = 'PAID') AS paid_count,
MAX(id) AS max_id,
SUM(version) AS version_sum
FROM shop_demo.orders;
SELECT id, status, version
FROM shop_demo.orders
WHERE id IN (1001, 1002, 1003)
ORDER BY id;行数相同仍不足以证明一致:一次漏插与一次重复可能抵消行数,更新漏掉也不会改变行数。这里增加 paid_count、version_sum 与逐主键核验,是为了暴露覆盖更新遗漏。生产还应按主键分块做校验,并加入订单金额、支付状态、库存守恒等业务不变量。
orders 的主键不是装饰。阿里云的 MySQL 源限制说明要求迁移或同步表具有主键或字段真正唯一的唯一约束;缺少二者时,DTS 无法稳定定位同一行,重试或全量与增量接续可能让目标出现重复记录。正向实验应先证明键值无重复;遗留无键表要在源端补键并重新演练,或从在线链路排除后使用可去重、可对账的专项方案,不能仅靠目标端事后 DISTINCT。
反向实验:让目标端失败对象暴露出来
为了验证团队能识别局部失败,可在临时目标库人为制造一个约束冲突。例如让目标表的 status 列比源端更短,或先插入与后续迁移主键冲突的数据,然后在源端写入会触发失败的记录。这个破坏性反例本次同样未执行,只能在可删除的合成环境按审批后的实验单运行。
-- 仅在临时目标库制造错误。
ALTER TABLE shop_demo.orders MODIFY status VARCHAR(4) NOT NULL;
-- 回到临时源库提交一条无法写入目标的变化。
UPDATE shop_demo.orders
SET status = 'REFUND_PENDING', version = version + 1
WHERE id = 1002;预期现象是任务或对象详情出现写入/执行失败,增量延迟可能持续上升,目标端 1002 保持旧值。证据应包括错误对象、失败 SQL 类型、目标端错误信息、延迟趋势和最后成功应用时间。此时不能用“总任务仍在运行”判定健康,也不能直接在目标端手改成期望值后切流。
修复时先停止会继续扩大差异的变更,恢复兼容列定义,再按 DTS 对当前任务与对象提供的恢复动作处理。随后重新观察失败对象归零、积压下降,并重新运行增量校验和业务不变量查询。若需要跳过失败 DDL 或排除对象,必须记录目标端最终结构由谁补齐;“跳过后任务变绿”只证明流水继续,不证明数据完整。
延迟必须拆成采集、积压和应用来看
增量延迟是切换前最常被误读的指标。零延迟不代表绝对没有差异,它可能只表示当前没有新事件;瞬时抬高也不必然是故障,大事务提交、批处理、全量争用 IO 或目标端维护都可能形成短峰。真正需要关注的是在相似负载下的趋势、积压是否持续增长,以及源端停止写入后能否在计划窗口内追平。
官方 DTS 增量延迟排查 将规格吞吐、源端大事务和目标端执行问题列为常见原因,并建议结合数据流与诊断能力判断是否触及实例处理能力。排查顺序可以这样收敛:
先确认源库是否仍有持续高写入或长事务,日志产生速率是否突增。再看 DTS 处理吞吐与积压趋势,判断是采集慢、转换暂存拥塞还是实例能力不足。最后检查目标库 CPU、IO、锁等待、索引、连接限制以及单个失败对象。
修复后观察延迟斜率是否反转,不能只截取一个瞬时低点。
容量计划还要覆盖日志保留。全量耗时越久,期间暂存的增量越多;任务长时间失败或暂停,恢复所需位点可能超出服务缓存或源端日志保留窗口。官方 运行错误排查 当前说明 DTS 缓存只保留最近 24 小时或 50 GB 的增量日志,并建议不要把运行任务暂停超过 6 小时;这些是服务边界,不是团队可以占满的恢复预算,源端日志还可能更早过期。位点或缓存已经消失时,重试不会凭空找回变化,通常要请求支持重读仍存在的数据,或重建全量基线。大库应在开工前估算全量持续时间、峰值变更量、源端日志保留和故障修复窗口,并考虑按对象拆分任务,避免一个冷门超大表拖垮整个迁移窗口。
校验结果要能定位和裁决差异
DTS 数据校验可以在不中断业务的情况下发现结构或数据差异,但它不是“自动证明所有业务语义正确”的按钮。官方 校验详情说明 提醒:全量和结构校验宜在任务完成后查看详情;增量校验应等当前位点经过相关变更时间后再判断;同一记录的多次变化可能被合并后校验,因此校验记录数不等于原始变更事件数。
校验发现不一致时,先判断是实时延迟造成的暂态、源端仍在更新、目标端有人直写、对象转换差异,还是确实漏数。差异报告至少带上对象、主键或分块、源值摘要、目标值摘要、源端提交水位、目标端应用水位与处置状态。包含真实字段值的报告应脱敏并限制下载权限。
修复策略要按权威侧决定。切换前源库是权威,通常从源端重放或重迁差异;切换后目标库成为权威,再拿旧源覆盖可能反向破坏新写入。全量校验发现差异后,人工修复还必须重新校验;增量校验的自动复核也只能消除暂态误报,不能替团队裁决业务冲突。
切换不是改连接串,而是转移唯一写入权
切换日先冻结非必要 DDL,并让发布、定时任务、消费者和后台脚本都进入同一变更窗口。只冻结 Web 流量而忘记消息消费者与批任务,旧库仍会产生新写入。建议把切换拆成可观察的状态:
追平前:源库唯一可写,目标库只允许 DTS 与校验账号写入。写冻结:停止所有旧库写入入口,记录冻结后的源端业务水位。最终追平:等待增量延迟回落,失败对象清零,校验位点越过冻结水位。
暂停正向任务:在控制台暂停迁移任务并等待状态确认,不把“已点击暂停”当成已经停止应用;保存最后位点、延迟、失败对象和任务状态。隔离目标写权:确认业务账号尚无目标库 DML 权限;若预演或部署曾提前授予,则先撤销或禁用。此时目标只保留迁移、校验和切换管理员的受控写权。读验证:在正向任务不再改变目标数据后,用只读影子请求和业务不变量确认目标库结果。
建立反向链路:以目标为源、旧源为目标创建并启动反向增量链路,确认起点、对象、循环防护、延迟与测试变更均符合预期。没有可用反向链路时,切换单必须明确回切不是无损的。写切换:反向链路验收后,才向目标业务账号授予写权、更新连接配置并灰度恢复写入,目标库成为唯一权威侧。观察期:旧源保持只读,不立即删除;回切条件、数据补偿方式和决策人仍有效。
DTS 的增量迁移不会因为“看起来追平”自动结束。官方术语说明明确,持续增量迁移或同步需要人工停止或释放。暂停前要保存任务配置、对象列表、校验结果、延迟趋势、失败对象为零的证据和最后业务水位。正向任务暂停、目标业务写权被确认隔离、反向链路已先于业务写入运行,是恢复写流量的三个独立门禁;任一项没有证据就取消切换。否则回切意味着明确丢弃观察期新写入,不能包装成无损回滚。
运行中、暂停、失败、完成描述的是任务控制状态,不是业务一致性结论。暂停只表示当前不再调度写入,恢复后仍要等待增量追平;失败可能已经消耗了可恢复缓存窗口;完成也仍需校验与业务不变量裁决。DTS 服务节点自身采用主备与断点续传,官方 架构说明 描述了节点异常后的自动切换,但这不覆盖源目标不可达、账号过期、源日志被清理、不受支持 DDL 或目标写入冲突。灾备设计必须把“DTS 节点故障”和“迁移链路失去可恢复位点”当成两类事件。
退出时同时清理数据面、权限和费用
退出顺序比“删除任务”更重要。先确认观察期结束且不再需要回切,再停止增量任务;导出必要的审计证据;对保留账号执行 REVOKE CREATE ON *.* FROM 'dts_reader'@'10.%';,或删除专用源目标迁移账号;移除 DTS 专用白名单、安全组与临时公网入口;删除经审批确认不再使用的心跳库、临时校验任务、测试表和差异导出;最后释放不再使用的任务实例。若直接删除账号或网络规则,任务可能先失败并持续积压;若只停任务不释放资源,则仍可能留下资源占用与费用。
-- 合成环境清理示例。生产必须先确认任务已退出且证据已归档。
DROP USER IF EXISTS 'dts_reader'@'10.%';
DROP USER IF EXISTS 'dts_writer'@'10.%';
-- 仅删除本次实验创建的库,绝不能把通配清理用于共享环境。
DROP DATABASE IF EXISTS shop_demo;费用治理不需要在架构文档写一个很快过期的金额,而要建立可追踪的资源台账。官方 DTS 计费项 当前说明:数据迁移使用按量付费,结构和全量迁移本身不收实例配置费,选择增量迁移后在增量运行期间计费,增量迁移暂停或失败时不计该项;目标接入方式为公网 IP 时还可能产生公网出流量费,数据校验也有独立计费规则。停止按钮并不删除实例或校验结果,完成后仍应按 计费方式说明 释放不再使用的实例。任务实例、运行规格、网络路径、数据校验、源目标临时扩容分别由谁批准,何时开始、暂停、完成和释放,超过观察期由谁收到提醒,都应进入台账。
架构选型:什么时候用迁移、同步或原生工具
DTS 数据迁移适合一次性上云、实例替换、机房搬迁或异构数据库迁移,并希望用托管控制面组织结构、全量、增量与校验的场景。若目标是长期双活、读写分离、跨环境持续复制,应评估数据同步任务及其冲突语义,而不是让一次性迁移永久化。若源目标同构、停机窗口充足、数据量可控,数据库原生导出导入或备份恢复可能更简单、更可预测。异构迁移还要把类型、函数、存储过程和 SQL 兼容改造纳入整体方案,数据搬过去不等于应用已兼容。
选择时至少比较六个事实:源目标组合是否被支持;全量期间源库能承受多少扫描;增量日志和 DDL 能否完整捕获;目标端是否能按峰值追平;校验能否覆盖关键对象与业务不变量;供应商退出时能否拿回配置、位点与差异证据。托管服务减少了运行采集进程的工作量,但不会消除数据库兼容、网络、安全和切换设计。
团队长期使用 DTS,应该沉淀迁移意图模板、权限模板、网络审批、对象兼容清单、校验脚本、切换状态机和退出清单。每次任务都指定业务 owner、数据库 owner、网络 owner、安全 owner 与最终裁决人。出现失败时,值班者能从任务、对象、延迟、数据库日志和校验报告定位;迁移结束后,任何临时凭证、白名单、资源和旧库都有明确到期动作。做到这些,DTS 才不只是一次控制台操作,而是一套可重复、可回滚、可退出的数据迁移能力。
真实项目接入时,还应把应用连接配置与 DTS 任务解耦。应用只引用“当前权威数据库”的配置键,发布平台负责把该键从源端切到目标端;迁移任务不能直接修改每个服务的连接串。连接池生命周期也要进入演练:配置中心更新后,旧连接是否主动排空,事务中的请求如何完成,后台进程是否会继续使用缓存密码,读写分离代理是否仍把请求送往旧库。否则控制台已经追平,应用层仍可能在切换后偷偷写旧端。
容量评审可以用一张简单的流量账解释:源端峰值每秒产生多少变更,DTS 稳态每秒能处理多少记录,目标端在保留索引和约束时每秒能提交多少,三者中最小值决定追赶速度。若全量阶段抢占源库 IO 后使业务长事务增加,日志生产速率还会反向抬高;如果目标端为了加速临时删除索引,则切换前必须重建并重新校验。团队要以演练曲线估算积压清空时间,并把源端日志保留窗口留出故障修复余量,而不是用某次低峰的瞬时吞吐外推整个迁移。
