ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

数据库迁移避坑指南:DTS全量与增量同步原理及实战

数据库迁移避坑指南:DTS全量与增量同步原理及实战 数据库迁移这件事做过的人都懂方案评审半个月真正干活就一个周末但那个周末能不能睡好觉全看你前面准备得有多细。我第一次用DTS做核心库迁移的时候自以为流程熟结果预检查就卡了三轮业务同事在旁边等得直跺脚。后来做得多了才摸清DTS数据传输服务虽然把数据迁移做成了可视化任务但背后该懂的原理、该避的坑一样都没少。这篇文章不打算重复官网那些配置手册而是把我实际跑迁移任务时踩过的坑、验证过的步骤、以及会推荐别人照着做的一套流程整理出来。无论你是要把自建MySQL迁到云上还是在两个云厂商之间搬家都可以拿这份笔记做参照。1. 先说清楚DTS到底帮你干了什么活1.1 迁移不是拷贝文件三段式才是核心很多刚接触DTS的朋友会把它理解成一个“高级拷贝工具”觉得把源库的表结构和数据搬到目标库就完事了。实际上DTS迁移任务默认是分三段走的结构迁移、全量迁移、增量迁移。结构迁移负责表、索引、视图、存储过程、触发器这类元数据在目标库落地。这一步如果源库和目标库的版本差异大最容易出兼容性问题。全量迁移把存量数据一批一批导过去。大表建议单独关注进度小表通常在几分钟内就能完事。增量迁移通过解析源库的binlogMySQL场景或redo/wal日志其他数据库场景把全量迁移期间业务新增的数据变化持续同步到目标库让两边差距从“小时级”缩到“秒级”。为什么要设计成三段因为真实业务不允许你停机慢慢拷贝。全量迁移可能跑几个小时这期间业务还在写库如果只做全量切库的时候必然丢数据。增量同步就是用来处理这段时间写入的它把迁移从“一次性复制”变成了“持续追平”。1.2 什么场景适合用DTS别把工具用错地方DTS适合的场景很明确数据库上云本地自建库迁到云RDS这是最常见的用法。跨云迁移比如从A云迁到B云只要网络能打通DTS可以处理。实例规格升级从一个规格的实例迁到另一个规格顺便整理表结构。搭建只读从库用DTS做持续同步比手动做主从复制省心。异地灾备把源库实时同步到异地目标库。如果只是临时导个数据文件、做一次性的离线导出导入那就没必要上DTS用mysqldump、DataX这类轻量工具更合适。DTS的价值在线上的“热迁移”不只是搬数据而是让切换时间窗口尽量短。1.3 DTS和DRS、自建脚本怎么选一张表格说清边界经常有人问DTS和DRS到底什么关系。其实DRS是另一个云厂商对数据复制服务的叫法能力上和DTS基本对标都是托管式的数据传输服务只是部署环境和控制台不一样。自建脚本的好处是免费、灵活但代价是断点续传、性能调优、冲突处理、数据校验这些能力全都要自己造轮子。方案全量增量断点续传数据校验运维成本适用场景DTS内置支持支持低生产环境热迁移、持续同步DRS内置支持支持低同类云环境下的迁移同步mysqldump同步脚本需自己拼需自建需自建高离线小数据量、临时导出DataX仅全量无无中批量离线数据交换我的建议是只要能走托管服务就别自己发明轮子。自己在脚本里处理binlog位点续传一旦中途断网或源库主从切换光Log Position对账就能耗掉大半天。2. 迁移前别急着建任务先花半小时做环境体检2.1 账号权限不是给个“读”权限就行DTS任务要顺利跑起来源库和目标库的账号权限都得提前配好。源库除了查询权限结构迁移还需要看视图定义、触发器定义的权限增量迁移则需要复制相关的全局权限。最小权限集可以参考下面这套-- 源库账号负责读取数据和拉取binlog CREATE USER dts_source% IDENTIFIED BY YourStrongPass1; GRANT SELECT, SHOW VIEW, TRIGGER ON *.* TO dts_source%; GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO dts_source%; FLUSH PRIVILEGES; -- 目标库账号负责写入和结构变更 CREATE USER dts_target% IDENTIFIED BY YourStrongPass1; GRANT ALL PRIVILEGES ON target_db.* TO dts_target%; FLUSH PRIVILEGES;不要图省事直接用root。权限太大不仅不合规真出问题排查时也很难确认是哪一步越权导致的。另外如果源库开启了MySQL企业审计或者安全策略记得提前把DTS所用账号加入白名单否则同步过程中可能会被审计规则拦截。2.2 网络连通与白名单预检查最常挂在这里预检查里出现频率最高的失败项就是网络不通。这里有个很容易踩的误区你以为源库和目标库都在同一VPC里就能直连实际上RDS默认开启的防火墙白名单可能只放行了本机IP。创建DTS任务时建议先做一次连通性测试常见网络方式有三种公网方式适合临时测试或数据量很小的场景需要源库开通公网地址并把DTS所在网段的IP加入白名单。VPC内网方式源库和目标库在同一个VPC内时首选走内网延迟低。专线/DTS专属通道跨地域、跨账号迁移时使用稳定性和带宽有保障但需要提前跟网络团队申请。我曾经遇到过一次神奇的现象源库ping得通预检查却说连接失败。最后发现是源库的本地防火墙只放行了3306但DTS探活用的端口是随机的。所以网络排查不要只看数据库端口还要确认出方向策略是否放行。2.3 binlog参数增量迁移的命脉增量迁移能不能跑起来很大程度上取决于源库的binlog配置。MySQL环境下重点检查这几项SHOW VARIABLES LIKE log_bin; SHOW VARIABLES LIKE binlog_format; SHOW VARIABLES LIKE binlog_row_image; SHOW VARIABLES LIKE server_id; SHOW VARIABLES LIKE max_binlog_size;log_bin必须为ON这是增量同步的前提。binlog_format必须为ROW。DTS需要精确知道每一行的前镜像和后镜像才能可靠回放STATEMENT格式记录的SQL语句在目标库执行可能产生不同结果。binlog_row_image建议为FULL否则某些场景下只记录变更列DTS可能无法还原完整行数据。server_id不能和DTS实例冲突否则拉取binlog会被拒绝。日志保留时长也要留意迁移大库可能耗时很久如果binlog只保留一天中途报错后无法从断点续传只能重来。2.4 字符集、时区、大小写今天省一步后面补三天字符集不一致是迁移后最常见的隐性bug。比如源库是utf8mb4目标库默认是utf8mb3表面上数据导过去了一旦表里存在emoji或生僻字就会变成问号。检查时要同时关注character_set_server和collation_server目标库表结构迁移后最好抽查几张表确认排序规则。时区问题也很容易翻车。如果业务代码用Java的JVM时区写数据源库和目标库却设置了不同的time_zone那么TIMESTAMP字段从二进制的UTC值转换出来时会出现时间偏移线上排查时最难发现的就是这种“看起来没问题但时间对不上”的怪病。大小写敏感参数lower_case_table_names也很关键。Linux环境下MySQL默认区分表名大小写Windows环境下不区分跨平台迁移时如果这个参数不一致应用层原来访问UserTable的SQL到了新库就可能产生“表不存在”的报错。我在预检查清单里会把这个参数和字符集一起核对每次都能发现一些隐藏风险。3. 配置迁移任务的完整链路从预检查到全量迁移3.1 创建任务时那几个容易忽略的选项创建DTS迁移任务大致的流程是选择源库和目标库实例填写账号密码选择迁移类型配置迁移对象提交预检查启动任务。这些步骤看起来很简单但有几个选项很多人不看就默认选后面会出问题。迁移类型建议选择“结构迁移全量迁移增量迁移”即使你现在只想做一次性迁移。因为真实环境下很难保证全量迁移这几小时业务完全不写入多一个增量迁移等于多一道保险最后切库时延迟追平就行。如果只选全量割接窗口就必须停写。迁移对象可以选择整个实例、指定库或指定表。建议按库维度选不要一开始就只想迁那几张核心表。一旦后续上线新表正向链路没包含这个对象增量阶段会直接跳过等业务切过去才发现漏表那就很被动了。再一个是冲突策略。当目标库已经存在同名对象或主键数据时有覆盖、忽略、报错三种处理方式。第一次做迁移的人我建议选“报错”这样至少能第一时间发现问题而不是让数据被悄悄覆盖之后对不上账面。3.2 预检查失败的两种真实情况与处理思路预检查相当于DTS在正式动手前帮你把环境体检了一遍失败不要慌一项一项看提示就行。我碰到过两类比较有代表性的失败。某次迁移源库开启了lower_case_table_names1目标库是默认的0。预检查直接报了“源和目标实例大小写敏感参数不一致”意思是迁移过去后表名大小写行为会发生变化应用侧可能立刻碰到“Table doesnt exist”。当时业务不允许改目标库参数最后的方案是在源库层面统一规范表名全部改成小写再重新触发预检查。另一类典型是“目标实例磁盘空间不足”。这个失败很实在不能忽略。全量迁移时DTS会把校验产生的临时表写入目标实例磁盘太满会导致同步进程卡死。解决方式不只是扩容还要顺手清理一下目标库中不需要的旧日志和临时文件。3.3 全量迁移阶段不要傻等盯住这几个指标全量迁移启动后任务列表里会显示迁移进度和速率。很多人看到进度条在动就去干别的了其实这个阶段有几个指标值得多看一眼。首先是迁移速率。如果大表速率掉到很低有可能是目标库写入性能成了瓶颈。MySQL的写入日志落盘频率、磁盘IOPS、实例规格都会影响导入速度。必要的时候可以临时升配迁移完再降回来花不了多少钱但能大大缩短割接窗口。其次是目标库监控。全量迁移过程中目标是持续写入的CPU和磁盘使用率会明显上涨。我见过有人把DTS和业务读写放在同一个实例上结果迁移任务一跑业务查询直接被拖慢。遇到这种情况建议设置任务限流或者把迁移放到业务低峰期。最后是不要在全量迁移过程中手动去目标库改数据。全量阶段DTS可能会分批清空并重建目标表你手动插入的数据很可能在下一次批次写入时被覆盖。任何校验都要等增量追平之后再做。4. 增量同步阶段DTS是怎么做到“边迁移边追平”的4.1 解析日志回放增量迁移的基本原理增量同步的原理可以简单理解成DTS起一个模拟从库的角色连接源库拉取binlog解析出每一条数据变更事件再转换成目标库能执行的SQL语句回放过去。所以源库的binlog格式必须是ROW否则DTS拿不到完整的行级变化记录。这里有个细节值得注意DDL也会通过增量链路同步过去。也就是说全量迁移完成后业务在源库执行的建表、加索引、改字段都会在目标库重放。如果目标库上已经手动做了同名变更就可能出现DDL冲突DTS通常会暂停增量任务等待人工处理。与其事后救火不如定个规矩迁移期间不要在目标库手动执行任何DDL。4.2 延迟监控多高的延迟要警惕增量迁移状态里通常会有一个“延迟时间”指标正常情况应该稳定在几秒以内。如果延迟持续增长而不是归零说明同步速度跟不上源库写入速度。延迟变高的常见原因有源库存在大事务。比如一条UPDATE影响了几百万行binlog会生成一条巨大的事务DTS需要整体拿到并逐行回放延迟自然飙升。目标库写入性能不足。回放SQL的并发能力受目标实例规格限制如果目标库CPU已经打满延迟会越积越多。网络带宽不足。跨地域迁移时这个尤其明显大量binlog在公网链路上传输带宽跑满就会持续积压。看到延迟升高不要慌先在任务监控页确认瓶颈在哪再对症下药。如果目标库性能不够临时升配往往立竿见影。4.3 冲突策略选错真的会翻车增量同步阶段最怕的是主键冲突。比如全量迁移完成后有人在目标库手动插入了一条和源库后续写入相同主键的数据增量回放时就会报错。DTS提供了冲突处理策略但不同策略的语义差异很大。覆盖以源库为准目标库已有数据会被覆盖更新。适合源库是权威库、目标库只是迁移副本的场景。忽略目标库已有数据时跳过源库的这次写入。适合目标库可能有补充数据的场景但会导致两边数据不一致。报错遇到冲突就暂停任务等人来处理。适合第一次迁移、需要严格校验数据的场景。我的经验是迁移过程中把策略设为报错切换前如果出现冲突逐条确认是目标库误写还是源库本身的主键分配问题切换完成后再考虑改成覆盖模式用于后续的双向同步场景。用固定的策略应对所有阶段迟早会出幺蛾子。5. 割接切换的黄金步骤不是点一下“完成”就行5.1 停写应用与最后追平切换前必须做对的两件事当全量迁移完成、增量延迟归零后就到了割接这步。这里必须明确一个原则切换动作不要靠“感觉差不多”要靠数据和流程。停写提前通知业务方停掉所有写入口。可以是发布系统里关掉写开关也可以是在数据库层面临时收紧账号权限。停写之后观察一段时间确认没有连接还在执行UPDATE/INSERT/DELETE。最后追平停写后让增量任务继续跑直到延迟显示为0。这时候源库和目标库的数据理论上完全一致记录下这个时间点作为后续校验的基准。很多事故都发生在这个阶段。有人觉得增量延迟已经很小了就不再等直接切库结果最后30秒的数据在目标库根本不存在。割接可以快但“快”的前提是增量已经归零。5.2 数据校验不能只看行数切库前一定要做数据校验。最基础的是行数对比但行数一致不代表数据内容一致——两边可能各有一条不同主键的数据正好数量一样。建议按这个顺序来做全表行数对比。可以用count大表用采样的方式降低压力。抽样内容校验。取几张核心表的若干行对比每一列的值确认没有乱码和精度丢失。时间字段校验。特别是更新时间列确认最近一小时的数据确实同步过来了。自增ID连续性。源库和新库如果自增步长设置不一致后续插入时可能因为主键冲突瞬间报错。DTS自带的数据校验功能建议开起来自动对比行数和校验和比人工写脚本省事得多。但自动校验通过后我仍然会随机抽查几张业务表毕竟有些隐藏的字段差异自动化工具不一定能发现。5.3 切换动作与回滚预案反向迁移链路不能省切换动作本身不复杂把应用连接串从源库改成目标库或者修改DNS解析让新的读写流量打到目标库上。真正复杂的是出问题之后的回滚。很多第一次做迁移的人会忽略一个关键操作在切换前创建一条反向迁移任务把目标库的增量变化同步回源库。这样做的好处是如果切换后业务验证不过关可以把应用切回源库同时源库已经有目标库这段时间的增量数据两边差距不会太大。没有反向链路回滚就只能手工补数据大库根本补不动。切换完成后的观察期也很重要至少持续一个业务周期比如一个交易日或者一个完整的24小时。不要切完不到一小时就宣布成功很多问题是在业务高峰时才暴露出来的。6. 实战踩坑与排查链路这些都是我实际处理过的6.1 坑1binlog_format不对增量同步起不来现象是增量任务状态显示“同步中”但延迟只增不减任务日志反复报错说无法解析binlog。我一开始以为是网络问题查了源库和目标库的连通性都没问题最后去翻了任务日志的错误码才定位到源库的binlog_format是STATEMENT。为什么STATEMENT不行因为DTS需要的是每一行的“前镜像”和“后镜像”STATEMENT格式只记录了SQL语句在目标库重新执行这条SQL时结果可能因为当前数据状态不同而完全不同。这不是DTS能力问题而是格式本身就不支持可靠同步。处理方式也简单把源库参数改为binlog_formatROW重启MySQL后确认binlog文件里已经按新格式写入再重新启动DTS任务。这个坑让我长了个记性创建迁移任务前环境体检清单里第一条就写binlog参数别再省这一步。6.2 坑2无主键大表把全量迁移拖进了泥潭有一张日志表几千万行没有主键。全量迁移一开始速率很慢而且目标库的写入延迟明显升高。更麻烦的是这种表在数据校验阶段不能用主键分批扫描DTS只能做全表扫描和全量对比数据库压力非常大。排查下来核心问题是这个表在源库的数据分布严重不均匀DTS默认的并发策略在无主键表上无法做到高效分片。处理方式分两步。短期内在迁移任务里给这个表单独设置较低并发度避免它拖垮整个实例长期来看我给这张表加了一个无业务含义的自增主键改造后再迁移速率翻了不止一倍。如果你也碰到这种历史遗留的无主键大表建议借迁移的机会顺手把表结构梳理一遍否则迁完之后每次做备份和查询优化都会很难受。6.3 坑3增量延迟飙升的一次完整定位有一次增量延迟从两秒一路涨到三十分钟业务方已经在群里问了。我的排查思路是分层的先看源库再看目标库最后看链路。先看源库监控CPU和IOPS都很平稳没有大事务在跑排除了源库自身压力问题。接着看目标库发现磁盘IOPS接近上限慢日志里全是INSERT语句每条都在一两秒。到这里基本锁定了目标库写入能力就是瓶颈。根本原因是全量迁移刚结束目标库的缓冲池还是冷的加上目标实例规格本来就不高增量回放的写入全部落盘磁盘很快被打满。解决方案是临时把目标实例升到更高规格并把磁盘IOPS上限调大延迟在十分钟内就降了回来。割接完成一周后再根据实际负载把规格降回去。这件事告诉我们延迟高不一定是DTS的问题先看两边实例的负载曲线通常很快能找到元凶。6.4 坑4字符集不一致迁移完才发现乱码这个案例最有代表性。迁移前检查了character_set_server两边都是utf8mb4结果某张表里的生僻字在目标库显示成问号。后来一查问题出在表的DEFAULT CHARSET上。老库的表很多是建表时指定的utf8mb3结构迁移时把表定义原样带了过去目标库里这张表还是utf8mb3存不下emoji。排查链路不太难先在目标库查出乱码行的十六进制发现是被utf8mb3截断的字节再对照源库表结构确认是表级字符集不一致。修复方式是先改表默认字符集再做一次表的字符集转换然后用DTS的全量校验确认数据一致。这个坑属于“整体参数对了但表级参数没查”的典型。现在我在环境体检时会专门执行一条SQL把字符集不是utf8mb4的表全部捞出来提前处理而不是等迁移完再救火。7. 收尾阶段验证清单与任务清理7.1 迁移完成后的对比验证清单切换完成不代表结束建议切完后的第一个业务周期按这份清单逐项确认业务核心报表的查询结果和迁移前一天的同一时点做对比。当天产生的增量数据在目标库中的记录数和金额汇总是否一致。定时任务、消息队列消费者的数据库连接是否全部指向了新库。监控告警里有没有出现权限、死锁、主键冲突类的报错。应用日志里有没有连接超时或数据库连接失败的记录。我见过有的团队切库后只测了主流程结果第二天定时报表跑出来数据对不上才发现有一个定时任务还连着旧库。割接这件事考验的其实是细心程度。7.2 资源和任务清理该扔的扔该留的留确认业务正常后DTS迁移任务建议保留一段时间不要马上删除。保留的目的是如果之后发现数据差异还能通过任务日志和位点信息排查。但也要注意正向任务保留期间一直在跑增量会产生费用建议在确认正常后删除或者直接停止任务。旧实例的处理要看公司策略。我一般建议至少并行运行一个完整业务周期再释放源库资源。如果源库本身就是本地机房的自建MySQL还要确认所有业务都已经切走再通知DBA下线避免开发本地直连旧库导致数据回流。7.3 写给第一次做迁移的人先拿小库全流程演练最后分享一个我觉得最值得养成的习惯任何一次DTS迁移无论体量大小都先拿一个小库或者某几张不重要的表把整条链路跑一遍。演练的目的不是为了测流程而是为了拿到一组真实时间数据预检查多久、全量迁移速率多少、增量追平需要多少秒、切库后校验耗时多久。有了这组数据大库迁移的割接窗口和资源调优才有依据。我还会把演练中发现的坑写成一页checklist迁移前逐项打勾。binlog参数、字符集、账号权限、网络白名单、冲突策略、回滚方案全部白纸黑字列出来。人的记性在压力下是靠不住的尤其在割接倒计时的环境下多看几眼那页纸也许就能避开一次重大事故。这套流程我用了很多次不能说完全不出问题但至少每次出问题都能快速定位到具体环节而不是对着失败任务满头问号。
返回列表