简介:阿里云专有云Enterprise版V3.16.0的数据传输服务DTS开发指南,是一份面向企业开发者与运维人员的官方技术文档。文档围绕DTS API接口展开,从产品法律声明、通用约定到快速入门,逐步讲解API调用流程与准备工作,包括登录API与工具控制台、查看API信息、获取AccessKey、STS AccessKey、公共Header参数及DTS的Endpoint。针对常用开发语言,分别给出了Java、Python、Go三种SDK调用示例,覆盖创建DTS实例、配置迁移/同步/订阅任务、启动与批量操作、消费组管理、任务查询与修改等核心场景,并提供接口的功能描述、参数说明、请求方法、请求URL与响应参数;同时包含命令行执行、变量设置等辅助说明,有助于减少联调排错成本。资源以单个PDF文件提供,压缩包大小约3.57MB,PDF格式便于离线查阅、检索与打印。目前已有71人学习下载,适合正在集成阿里云专有云DTS服务、希望快速上手API开发的工程师参考。
1. 专有云Enterprise V3.16.0里的DTS:先弄清楚它到底给你开放了什么
如果说公有云上的数据传输服务DTS是一个开箱即用的控制台工具,那专有云Enterprise版 V3.16.0里的数据传输服务DTS,更像一个嵌在你私有环境里的数据管道基础设施——它的控制台只解决“人点一下”的问题,真正要跟你的运维平台、自动化发布流程、数据治理系统打通,靠的是它背后那套开放API。很多从公有云转过来的开发者第一次上手就卡住:拿公有云的接口文档直接调,签名过了、Endpoint却不通;或者任务建出来了,状态轮询逻辑写得不对,把迁移进度当同步延迟看,闹出不少误会。
这篇开发指南要解决的就是这件事:在专有云Enterprise版 V3.16.0这个环境里,DTS开发到底要从哪里下手——Endpoint和访问控制怎么确认、SDK骨架怎么搭、任务的创建/轮询/清理怎么串成一套可复用的代码流程、任务配置里那些规格和策略参数到底该怎么设,以及专有云环境里特有的几个坑。适合正在做政企项目、私有化交付或内部数据中台的集成开发、运维工程师和刚接手专有云DTS的开发者。下面的内容不依赖任何控制台点击,全程用API思路讲,照着敲就能跑。
2. 接入前最要紧的三步:Endpoint、访问控制与SDK骨架确认
2.1 先确认你手里的Endpoint是哪个:专有云和公有云的第一个分岔
专有云环境里的DTS服务,API入口不是你熟悉的公网域名,而是部署平台内部API网关暴露出来的内网地址。这个地址长什么样、在哪个可用区、走HTTP还是HTTPS,不同环境完全不一样,标题里V3.16.0只告诉你版本,不告诉你地址。常见做法是找平台管理员要“服务目录”或“API网关端点清单”,里面按服务名列出DTS的访问域名和协议。
拿到地址后别急着写代码,先用两三个请求把连通性确认掉。我一般会用curl直接探一个只读接口,确认网络通、域名解析正常、网关能响应。下面这段就是探活的最小命令:
# 替换为你的专有云环境实际Endpoint,例如 dts-internal.10.0.0.8 DTS_ENDPOINT="https://dts.${YOUR_DOMAIN}" # 随便传一个不完整但合法的请求,观察网关返回 curl -k -X GET "${DTS_ENDPOINT}/openapi/version" \ -H "x-request-date: $(date -u +%Y%m%dT%H%M%SZ)" \ --connect-timeout 5 --max-time 10这段命令背后的逻辑是:先让请求打到网关上,看返回的是“签名缺失”还是“连接超时”。如果返回签名类错误,说明网络链路通,API网关是活的;如果返回404或路由错误,说明Endpoint写错了或服务名不对;如果连接超时,就要查安全组、路由表这些网络策略。参数说明:x-request-date是专有云网关常见的公共请求头之一,很多环境要求请求头里带UTC时间的版本,格式固定不能随意改;-k在正式环境不安全,探活时可以临时用,正式代码里应该走网关信任链。
连接探活这一关过了,再进入签名环节。有的环境网关还要求先拉取一个公开的API版本清单,你可以通过这个清单直接看到DTS暴露了哪些接口,省得去翻文档对参数名——专有云V3.16.0的接口参数跟公有云有出入,这个我们后面避坑章节专门讲。
2.2 访问控制:不是AK直接调DTS,而是先换Token再调接口
专有云里DTS的API调用链通常不是“拿AK/SK直接签名业务请求”,而是分成两步:先用一个全局的访问凭证去换取短期Token,再用Token去调具体业务接口。这么做是为了统一管控所有云服务的API访问,同时让Token有过期时间,避免长密钥散落在各个业务系统里。
import hmac, hashlib, base64, datetime, requests def get_dts_token(ak: str, sk: str, token_endpoint: str) -> str: # 签名串按key的字典序拼接 params = { "AccessKeyId": ak, "Action": "GetDtsToken", "Format": "JSON", "SignatureMethod": "HMAC-SHA1", "SignatureVersion": "1.0", "Timestamp": datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"), "Version": "2019-06-01", } # 构建待签名字符串:GET & 百分号编码后的路径 & 排序后的参数 sorted_params = "&".join(f"{k}={params[k]}" for k in sorted(params)) string_to_sign = f"GET&%2F&{quote(sorted_params)}" # HMAC-SHA1签名,key是 sk + "&" digest = hmac.new( (sk + "&").encode("utf-8"), string_to_sign.encode("utf-8"), hashlib.sha1, ).digest() params["Signature"] = base64.b64encode(digest).decode("utf-8") # 发起Token换取请求 resp = requests.get(token_endpoint, params=params, timeout=10) return resp.json()["Token"]这段代码的要点有三个。第一,签名串拼接是所有专有云API的公共约定,参数必须按字典序排好,再整体做URL编码,这里quote函数要特别注意,它默认不转义/,但签名规范里要求转义,所以实际要传一个safe=''才行,这是最常见的签名翻车点。第二,SignatureMethod和SignatureVersion必须原样传,有的环境只认HMAC-SHA1,有的支持SHA256,先在探活阶段确认。第三,Token换取接口的Action名称在不同版本里可能不一样,有的叫GetToken、有的叫AcquireDtsToken,如果你的环境报InvalidAction,说明名字不对,不要硬猜,回到平台的服务清单里核对。
Token拿到后,它的有效期通常只有几十分钟到几小时不等。开发时最容易踩的坑是把Token当AK一样全局缓存,结果Token过期后调DTS接口报InvalidToken,排查半天以为是代码问题。我一般会在封装层加一个“过期前5分钟自动刷新”的逻辑,而不是每次调用都现取——既减少网关压力,也不至于在任务调度中途因为Token过期被打断。实际上,网关对该Token的校验到了秒级,你本地存的和网关判定的过期时间可能差一分钟,预留5分钟刷新是够用的。
2.3 最小可用的Python SDK调用骨架:拿一个任务列表接口练手
不管后面要做什么开发,先调通一个真正的DTS业务接口,才能确认Token、签名、网络参数全链路OK。最合适的练手接口是“查询迁移任务列表”,它是只读操作,不会在数据链路上产生副作用。注意这里不要直接用公有云的SDK,因为专有云的Endpoint、公共参数和API版本都不同,最稳妥的做法是直接用requests按公共规范组装请求。
import requests def call_dts_api(endpoint: str, token: str, action: str, params: dict, version: str = "2019-06-01"): """ 专有云DTS通用请求封装 endpoint: 从平台服务目录拿到的DTS API地址 token: get_dts_token()获取的短期凭证 action: DTS接口名,例如 DescribeMigrationJobs params: 业务参数dict version: API版本号,以平台服务清单为准,不要照抄 """ payload = { "Action": action, "Version": version, "Format": "JSON", "AccessToken": token, # 注意:专有云DTS一般用这个参数携带Token "RegionId": "cn-xxxx", # 专有云RegionId通常是环境自定义ID } payload.update(params) resp = requests.post(endpoint, data=payload, timeout=15) if resp.status_code != 200: # 把网关原始响应打出来,排错信息全在这里 raise RuntimeError(f"API call failed: {resp.status_code} {resp.text}") body = resp.json() if "Code" in body and body["Code"] != "Success": raise RuntimeError(f"API error: {body.get('Code')} {body.get('Message')}") return body # 实际调用:查当前环境里所有迁移任务 result = call_dts_api( "https://dts.${YOUR_DOMAIN}", token=my_token, action="DescribeMigrationJobs", params={"PageSize": 10, "PageNumber": 1}, ) for job in result.get("MigrationJobs", []): print(job["MigrationJobId"], job["MigrationJobName"], job["Status"])这个骨架把调用细节收敛到一个函数里,后面所有DTS开发都复用这一层。说明一下三个关键设计:一是请求用POST而不是GET,因为DTS业务接口往往带着一大段JSON配置,POST更不容易碰到URL长度限制;二是Token放在AccessToken这个参数名里,但不同专有云版本有叫Token或DtsToken的,以实际版本为准;三是网关错误码和业务错误码是完全分开的,resp.status_code != 200是网络链路问题,body["Code"] != "Success"是业务问题,两个不放在一起判断,排错效率高很多。RegionId这个参数也不要忽略,专有云里环境自定义的Region字符串不能复用公有云那套。
3. 用API走完一个DTS任务的生命周期:创建、启动、轮询与清理
3.1 任务类型先分清:数据迁移、数据同步、数据订阅的适用边界
DTS在开发接口里开放的SKU比控制台看到的更细,本质是三类引擎:数据迁移(一次性搬迁上云/下云)、数据同步(实时增量在多个库之间流转)、数据订阅(把增量变更以消息形态给下游消费)。很多人在专有云项目里把迁移和同步混着用,导致任务配置写错、链路规格买贵,等到跑起来才发现不是想要的效果。
| 任务类型 | 典型场景 | 数据流向 | 是否常驻 | 增量能力 |
|---|---|---|---|---|
| 数据迁移 | 机房搬迁、新旧库替换、上云 | 源到目标一次性/限期 | 短周期 | 支持增量追平后自动停机 |
| 数据同步 | 实时数仓、双活、读写分离 | 源到目标持续同步 | 长周期 | 持续增量,延迟常驻监控 |
| 数据订阅 | 消息驱动、变更捕获 | 单一来源分发给多个消费者 | 长周期 | 只读取,不写入目标库 |
在API选型上,三类对应不同的Action前缀,创建任务的参数结构也有明显差异。数据同步任务通常还会要求你预定义一个同步初始化的方式(比如是否先做全量再做增量),这在接口里表现为需要传同步初始化配置而不是迁移的“结构+全量+增量”三段开关。做选型时不能只看当前需求,要问一句“这个任务三个月后还跑不跑”——如果跑,选同步而不是迁移;如果只是帮客户做一次割接,选迁移,因为迁移任务在数据追平后自己会进入完成态,不占链路资源。
3.2 创建任务:一张配置JSON讲清楚最核心的字段
创建数据迁移任务是DTS开发里最基础也最绕的一步。专有云V3.16.0的创建接口接收一个大JSON,里面嵌套了源库、目标库、迁移对象、迁移阶段、链路规格、网络设置。下面这张配置是我在模拟项目X里用于把一个MySQL实例搬到新架构的最小配置,实际开发时直接在这个结构化JSON基础上改字段即可。
{ "MigrationJobName": "sim-project-user-center-migrate", "MigrationJobType": "MIGRATION", "SourceEndpoint": { "InstanceType": "RDS", "InstanceId": "rm-bp1xxxx", "Engine": "mysql", "RegionId": "cn-xxxx-01", "DatabaseName": "user_center", "UserName": "dts_rw", "Password": "encrypted-by-kms" }, "DestinationEndpoint": { "InstanceType": "RDS", "InstanceId": "rm-bp2yyyy", "Engine": "mysql", "DatabaseName": "user_center_new" }, "MigrationMode": { "StructureMigration": true, "FullDataMigration": true, "IncrementalMigration": true }, "MigrationObject": [ { "DBName": "user_center", "IncludeTable": ["user_account", "user_profile"], "ExcludeTable": ["tmp_log_*"] } ], "MigrationJobSpec": "small" }逐段说。SourceEndpoint和DestinationEndpoint是两个对称结构,但注意目标端通常不传UserName和Password,迁移任务执行时DTS会用源端账号读取数据、用你在任务预检查阶段配置的目标库账号写入数据,两个段的账号体系是分开管理的。MigrationMode里的三个布尔值表示迁移阶段开关,生产环境建议全开true,这样结构、历史数据、增量变更一次跑完,任务会在增量追上后自动进入完成状态。MigrationObject用DBName加IncludeTable/ExcludeTable做白名单和黑名单过滤,支持通配符,比如tmp_log_*会把以tmp_log_开头的表排除掉,这个在迁移日志类表时特别实用。
参数选择上有一个经验:InstanceId字段在专有云里不一定填云实例ID,如果你的源库是自建ECS上的MySQL,InstanceType要改成ECS或ON_PREMISE,同时要补上Host和Port字段。换句话说,InstanceType决定后面必须跟哪些关联字段,填错了预检查阶段直接报“实例类型与连接信息不匹配”。还有MigrationJobSpec,这是链路规格——small是最小档,对应较低的性能上限,开发联调阶段完全够用,不要一上来就买xlarge,我们在第4章专门讲。
3.3 启动与状态轮询:用轮询脚本盯住迁移进度
创建任务后它不会自动跑,必须显式调用启动接口;启动后任务进入一个状态机流转。专有云DTS迁移任务的状态大致是:NotStarted(已创建未启动)、Prechecking(预检查)、Migrating(迁移中)、Finished(迁移完成)、Suspended(暂停)、Failed(失败)。开发集成时,最大的工程点是写一套可靠的轮询逻辑,而不是在控制台刷页面。
import time def wait_migration_finish(job_id: str, interval: int = 30, timeout: int = 7200): """ 轮询迁移任务直到进入终态或超时 interval: 轮询间隔秒数,默认30秒一次 timeout: 单次任务最长等待秒数,默认2小时 """ waited = 0 while waited < timeout: status = call_dts_api( "https://dts.${YOUR_DOMAIN}", token=my_token, action="DescribeMigrationJobStatus", params={"MigrationJobId": job_id}, )["Status"] if status in ("Finished", "Failed"): return status if status == "Suspended": raise RuntimeError(f"job {job_id} suspended, need manual intervention") # 迁移中打印当前进度和数据积压量,方便排查 print(f"[{time.time()}] {status}, " f"progress={status_detail.get('Progress')}, " f"delay={status_detail.get('IncrementalDelaySeconds')}") time.sleep(interval) waited += interval raise TimeoutError(f"job {job_id} not finished in {timeout} seconds")轮询的坑在于,状态不是单调递增的。预检查可能因为账号权限不到位反反复复;迁移中如果源库有大事务,延迟很大但不代表卡死。我在代码里两个处理习惯:一是把Suspended视为异常状态抛出,而不是继续苦等,因为Suspended往往意味着人工介入(比如磁盘满了、账号被改);二是每次都把IncrementalDelaySeconds打印出来,这个字段只有在进入增量迁移阶段才有值,如果迁移卡在全量阶段,它会一直是空的或显示-1——看到-1不代表延迟为负,而是“当前不处于增量阶段”,别让监控告警误报。轮询间隔建议不要低于20秒,专有云网关对Describe类接口也有QPS限制,太频繁的轮询反而会触发限流返回Throttling。
4. 任务配置参数怎么定:规格、三阶段、限流与脏数据策略
4.1 链路规格选型:small到xlarge各有各的适用面
DTS同步/迁移链路在专有云里是按规格售卖或分配资源的,规格决定读写并发上限和内存占用。选配置不是越大越好,专有云是共享资源池,一条xlarge链路把平台IO打满,会拖累同一台宿主机上的其他任务,这种事故见过不止一次。
| 规格 | 参考写入吞吐 | 适用场景 | 资源占用特征 |
|---|---|---|---|
| small | 数百行/秒 | 联调、小表、低频同步 | 极低,适合开发环境常驻 |
| medium | 数千行/秒 | 单库常规业务、中小表全量 | 中等,不会明显抢占带宽 |
| large | 数万行/秒 | 大库搬迁、多表并行迁移 | 较高,需评估源库IO压力 |
| xlarge | 十万级行/秒 | 数仓同步、巨型实例迁移 | 高,非必要不要常开 |
我的经验是三个判断维度:第一,任务持续时间。联调或一次性迁移,按峰值流量选,迁完就释放;常驻的增量同步,按平均值选,给50%余量。第二,源库能力。规格再高,源库主从延迟扛不住,链路也是空转,所以选规格前先看源库的QPS和IOPS。第三,专有云平台的剩余容量。某公司之前在专有云环境里直接选xlarge,任务一启动全平台IO告警,最后灰溜溜改成large并限流——规格参数不是给你一个人的,是整个平台在分摊。不同规格在API里对应的MigrationJobSpec值是固定的枚举,不能自定义中间档,选型拿不准时选高一档但开限流,比选低档然后反复重试任务更省事。
4.2 三阶段开关怎么组合:不是每次都要全开
创建迁移任务时的三个布尔选项,很多开发者无脑全开,但有些场景全开反而是错的。比如你只是帮业务补一张维表,表结构已经手工建好了,结构迁移就没必要开;再比如源库是Oracle,目标库是PG,结构迁移会把Oracle的字段类型映射成不合理的PG类型,这种跨引擎场景,我通常只开全量和增量,结构让业务方自己用建模工具处理。
常见组合和适用场景我用表格给你拆开:
| MigrationMode组合 | 适用场景 | 需要注意的点 |
|---|---|---|
| 只开StructureMigration | 建库建表,不搬数据 | 依赖DTS类型映射,跨引擎慎用 |
| StructureMigration + FullDataMigration | 一次搬迁,之后业务停机切换 | 停机窗口内必须完成全量 |
| FullDataMigration + IncrementalMigration | 已有结构,需要追平增量后切换 | 源库binlog保留时长要够 |
| 三个全开 | 复杂迁移,需要最短停机 | 预检查项最多,周期最长 |
参数层面的建议:三阶段全开时,务必确认源库的binlog/归档日志保留时长大于任务预计跑完全量的时间。专有云里很多MySQL实例binlog只留24小时,全量迁移跑了两天,增量阶段从第一天开始拉,结果binlog已经清理,任务直接失败,没有后悔药。开发时可以在创建任务前先查一下源库binlog保留时长,或者用DTS自带的预检查功能,它会自动帮你校验这个条件。
4.3 限流与脏数据策略:两个藏得很深但决定成败的参数
相比规格和阶段,限流和脏数据策略参数在创建API里不是必填项,所以容易被忽略。但不配这两个参数,等于让DTS全速跑、遇到脏数据就中止,两个极端都是问题。限流参数控制在数据迁移或同步过程里DTS对源库的读出速率,脏数据策略控制增量同步阶段遇到目标端主键冲突、约束冲突时怎么办。
{ "MigrationJobId": "dtsjob123456", "SpeedLimit": { "Enable": true, "MaxReadSpeed": 50 }, "ConflictResolution": { "Type": "INTERRUPT" }, "ConnectionCharset": "utf8mb4" }SpeedLimit里MaxReadSpeed的单位在专有云环境里通常是MB/s,它的作用是给全量迁移阶段划定源库读取上限。比如源库是正在承载线上业务的MySQL,全量扫描本来就会增加IO压力,你不限流,可能迁移没跑完先把业务库拖垮。经验值:线上业务库限20-50MB/s,离线库可以放到100MB/s以上。ConflictResolution的取值影响增量同步遇到数据冲突时的行为,INTERRUPT表示任务停下来等人工处理,IGNORE表示跳过冲突继续跑。从数据一致性角度,我强烈建议选INTERRUPT——选IGNORE等于允许目标端数据静默不一致,后面核对数据时你根本不知道丢了多少条。这个参数在任务运行中是可以通过更新接口动态调整的,所以真遇到大批量冲突需要快速追进度时,先调整成IGNORE跑过去,然后立刻手工对账,这是一线排障的常见玩法。
这里补充一个高价值的参数是ConnectionCharset,专有云环境里这个字段如果漏配,DTS会用默认字符集去解析源库binlog。源库是utf8mb4、目标库也准备建utf8mb4,但DTS连接源库时按utf8解析了特殊字符,中文可能没问题,emoji和生僻字就会变成乱码且不报错。开发时要么显式配这个参数,要么在预检查阶段强制做一个源和目标字符集的专项校验,别等到业务验收时才发现。
5. 避坑盘点:专有云DTS开发中五个绕不开的现场问题
5.1 按公有云文档传参,接口报InvalidParameter或SignatureNotMatch
现象:从公有云拉了一份DTS的SDK示例,改了Endpoint和AK/SK后直接跑,创建任务时报InvalidParameter,甚至签名校验都过不去。
原因:专有云Enterprise V3.16.0的DTS OpenAPI虽然操作语义和公有云相同,但参数命名、API版本号、公共头格式都有差异。最典型的差异是Token传递方式,公有云SDK里很多接口直接把AK/SK放进签名,专有云必须先换Token;此外,API版本号也不是你熟悉的那个年份版本。
解决:第一步,让平台管理员给你拉一份该环境DTS的服务目录,里面通常附带接口定义文件或API文档页面,以那个为准。第二步,先用脚本拉取接口列表,对比你要用的Action是否存在于当前版本;存在再比对参数结构。不要花时间猜公有云和专有云的差异,直接以环境内实际定义为准。
5.2 迁移账号权限过高,源库出现锁等待和从库延迟
现象:全量迁移启动后,源库CPU没飙高但锁等待明显变多,从库show slave status里的Seconds_Behind_Master持续增长。
原因:很多开发图省事,给DTS迁移账号一次性授了ALL权限。DTS连接源库后会做表结构采集和一致性快照读取,权限过高时它可能额外获取了锁相关的元数据,加上全量扫描本身的行读,放大了对源库的影响。而限流参数没开,DTS会按最大速率去读。
解决:给迁移账号按最小权限原则配:SELECT、SHOW VIEW,必要时加LOCK TABLES(一致性快照需要)。同时把SpeedLimit打开,限制读取速率。一个附加建议:全量迁移尽量安排在业务低峰期。专有云环境里DTS和业务共享底层资源,源库出现性能问题时会反向拖慢整个迁移进度,两败俱伤。
5.3 大事务导致增量延迟飙升,几千秒都追不平
现象:源的oltp业务在高峰期提交了一个批量更新大事务,之后DTS的增量延迟从1秒飞到2000秒,并且这个延迟长时间稳定不降,看起来像卡死。
原因:目标端回放是串行的,大事务在目标端只能按单线程执行。源端大事务执行了30秒,DTS在目标端可能要执行5分钟;如果源端持续高并发提交事务,目标端消费速度低于生产速度,延迟只会越拉越大。这不代表任务坏掉了,而是链路回放速率的上限就在那。
解决:处理这问题要分两层。如果延迟还能接受,等着追平就行,期间不要反复暂停重启,每次重启还要清位点,只会雪上加霜。如果延迟已经影响业务切换窗口,就要从源头拆事务:让业务侧把大批量UPDATE拆成小批次,同时适当提高DTS增量回放的并发连接数——专有云的增量回放并发参数通常是任务级的一个独立配置项,有些版本能用ParallelThread调整,在源库负载允许的前提下加大并行度,延迟会快很多。
5.4 字符集不一致,全量迁移后中文正常但emoji乱码
现象:迁移任务全程无报错,数据行数完全一致,但字段里的emoji和部分生僻字变成问号或乱码。更隐蔽的是,只有个别字段有这个现象,不是整表乱码。
原因:DTS连接源库时,如果连接层字符集不是utf8mb4,就会被降级成utf8或Latin1。源库表本身是utf8mb4,但DTS的会话连接串没指定字符集,使用了默认配置。全量阶段还能靠数据库内部编码转换蒙混过关,增量阶段从binlog里解析出来的字符被错误解码后写进目标库,乱码就产生了。
解决:在创建任务的连接配置里显式增加ConnectionCharset字段,设成utf8mb4;同时检查目标库连接串的charset参数。我在每个含字符串字段的迁移项目里,都会专门挑一条含emoji的测试数据加入预检查。用一个小技巧:迁移前在源库执行SELECT CONVERT('中文emoji😀' USING utf8mb4)把结果记录下来,迁移后在目标库跑同样的查询比对,能秒级定位字符集问题。
5.5 任务暂停后再启动,目标端主键冲突暴增
现象:因业务变更需要暂停同步任务,暂停期间业务侧还在照常写入目标库;几小时后重新启动任务,任务很快进入异常,日志里一堆主键冲突。
原因:暂停期间目标库继续接收业务写入,而源库的增量变更也在持续累积。当任务恢复时,DTS会从暂停前的位点继续拉增量数据,这段位点区间的数据可能和目标库已有的业务写入冲突,尤其是那些主键由业务侧生成、不依赖数据库自增的表,冲突概率非常高。
解决:如果是计划内暂停,标准操作是先让业务对目标库停止写入,或者记录下暂停位点,恢复时跳过冲突段。API里做两件事:一是暂停前调用停止接口把位点记下来,二是恢复时配置冲突策略为IGNORE跳过重复数据,并立即跑一次数据校验确保两边一致。不要天真地以为暂停期间两边都闲着,只要目标库还有任何写入口,重启必打冲突。这个坑在专有云里更明显,因为业务系统可能挂着多个数据入口,不是你能完全控制的。
6. 进阶:延迟分级监控与手动校验的习惯
6.1 延迟监控不要只看一个秒数,按位点差距分三级
增量同步任务的延迟监控,很多团队的告警口径是“超过60秒就报警”。但等延迟涨到60秒再处理,往往已经晚了。我现在的做法是按增量位点差距分三级:位点差距小于5秒属于健康,5到30秒需要观察,超过30秒立即介入。怎么拿到位点差距?DTS的Describe接口里会返回主库当前位点和DTS已消费位点两个字段,两个位点的文件号和偏移量相减就能算出真实差距。
# 伪代码:计算源库和DTS消费位点的文件偏移差 source_binlog = get_source_master_status() # ('mysql-bin.000121', 4096) dts_position = get_dts_consume_position(job_id) # ('mysql-bin.000119', 18920) # 文件号差2,说明DTS落后了两个binlog文件,延迟大概率超过秒级 delta_files = int(source_binlog[0].split('.')[-1]) - int(dts_position[0].split('.')[-1])这个做法的价值在于,秒数延迟是一个间接指标,受大事务、网络抖动影响大;位点差是直接指标,反映DTS实际消费到哪个位置,对排障更有指导意义。你不用担心具体算出来的值是否精确到字节,只要文件号差距从0变成1、2、3,基本可以断定同步链路出问题了。
6.2 每次集成结束前,保留一个手动校验脚本的习惯
API层面DTS自带的数据校验功能在专有云里不一定覆盖所有场景,尤其是跨引擎迁移时的类型映射,可能出现数值精度问题。我的习惯是每个迁移项目都留一个独立的校验脚本:对每个迁移对象表做COUNT对比,再对涉及金额、时间戳、字符串长度等敏感字段做SUM或抽样。这个脚本不复杂,但能帮你在任务显示完成之后,再做一道兜底防线。
# 简单的双端COUNT校验骨架 def verify_table_count(src_conn, dst_conn, table_name): src_cnt = src_conn.execute(f"SELECT COUNT(*) FROM {table_name}").scalar() dst_cnt = dst_conn.execute(f"SELECT COUNT(*) FROM {table_name}").scalar() if src_cnt != dst_cnt: raise SystemExit(f"[FAIL] {table_name}: src={src_cnt} dst={dst_cnt}") print(f"[PASS] {table_name}: {src_cnt} rows matched")这里的COUNT校验不能替代全量哈希比对,但它成本低、见效快,适合做每一个任务上线前的例行检查。真正要求严格的环境,再加一层按主键分桶的哈希校验,但那是另一套工程,不是每次集成都需要。
6.3 关于规格选型的一个血泪教训
最后说一个真实习惯。某次在专有云项目里做割接,图省事把迁移任务规格设成了xlarge,一启动就把存储节点的IO打满,周边业务的写延迟从2毫秒涨到200毫秒,平台告警直接炸了。那次之后我给自己定了一条死规矩:任何常驻任务,规格初始值一律从medium开始;一次性大迁移,选large并要求平台确认容量,不许直接上xlarge。规格可以升,但一开始就用大规格把平台资源抢走,后面的运维沟通成本非常高,这个教训让我后来所有DTS工程的资源规划都先看共享容量再定规格。
另外,养成每次做完开发后把任务用量、延迟曲线、位点信息导出一份备份的习惯。专有云平台有时候会做资源回收或版本升级,你导出的这套数据是后续排查问题和重新搭建链路的依据,这比任何API文档都实在。希望这篇开发指南能帮你在专有云Enterprise V3.16.0里少走几趟弯路,把DTS真正接稳。
本文还有配套的精品资源,点击获取