跨地区MySQL迁移提速:压缩算法与带宽限制实战指南
2026/9/12 2:27:04 网站建设 项目流程

凌晨两点,你盯着屏幕上不断跳动的传输进度,几百个G的MySQL数据要从A地机房迁到B地机房,窗口只有四个小时。合同上明明写着100Mbps带宽,可实际传输速度就是跑不满,眼看着剩余时间一点点被吃掉,那种感觉只要经历过一次就忘不掉。跨地区数据库迁移最让人头疼的地方就在于:真正卡住你的往往不是数据库本身,而是网络这堵墙,以及你对待这堵墙的方式。这篇文章不聊MySQL安装配置,也不扯存储引擎底层原理,就聚焦一件事:跨地区MySQL数据迁移时,如何用数据压缩和带宽限制把速度真正优化上去,让迁移从"听天由命"变成"可控可算"。

1. 把耗时账先算明白:带宽、延迟和传输量到底谁在拖后腿

1.1 迁移时间不是"数据量÷带宽"这么简单

很多人一开始都习惯拿数据总量除以带宽来估算时长,比如300GB数据、100Mbps带宽,一算觉得“顶多六七个小时”。但实际一跑就傻眼了:一小时才传了几十个GB,跟预期差了一大截。问题就出在“跨地区”这三个字上。

跨地域的网络链路并不是你独享的物理管道,数据要经过多段路由、多个运营商节点,延迟和丢包都会直接影响TCP的传输效率。TCP单个连接的吞吐量受往返时延(RTT)和拥塞窗口共同限制,当RTT很高时,窗口增长得慢,单条TCP流根本打不满带宽。比如同样是100Mbps链路,同城可能轻松跑到90Mbps以上,跨地域可能只能跑三四十Mbps,丢包一高甚至更低。

所以在规划迁移之前,先别急着算理论值,一定要用工具实测两端之间的真实吞吐。我的习惯是拿一小段数据先"探路":

iperf3 -c 目标IP -P 4 -t 60

这个命令会用4个并发流测60秒,能直观看到多流并发时能达到多少带宽。如果单流只有30Mbps,四流能到80Mbps,那就说明单连接是瓶颈,后面迁移时应该适当增加并发。如果四流也上不去,那就要考虑链路本身的质量和限速策略了。

1.2 一个具体的耗时测算例子

拿一个我实际遇到过的场景来算账。当时要从一个老机房迁到另一个区域的云上实例,逻辑导出的SQL文件总共300GB,用工具实测下来源端到目标端的有效吞吐大概是6MB/s,约等于48Mbps,离合同带宽差得很远。

  • 不压缩直接传:300 × 1024 ÷ 6 ÷ 3600 ≈ 14.2小时
  • 压缩比3:1后传输量变成100GB:100 × 1024 ÷ 6 ÷ 3600 ≈ 4.7小时
  • 再把并发流从1提到4,如果链路余量足够,时间还能进一步缩短

从这个例子就能看出来,跨地区迁移时"数据压缩"往往是性价比最高的优化手段。它不是赌网络质量,而是直接减少需要传输的字节数。带宽越窄,压缩收益越明显;带宽很充裕时,压缩的CPU开销反而可能成为新的瓶颈,所以要动态取舍。

1.3 备份与迁移要把CPU、IO开销一起算进去

压缩不是免费的,它消耗源机的CPU,目标端解压还要额外消耗目标机的CPU和磁盘IO。如果源库本身就是高负载的线上实例,压缩级别调得太高,可能会影响业务。解决思路有两个:一是把压缩级别调低,让压缩速度跑起来;二是用专门的备份机或从库来承担导出和压缩工作。后面章节会详细聊算法选型,这里先记住一个原则:跨地区迁移的性能优化,本质是CPU、带宽、磁盘IO三者之间的平衡,哪个是短板就先补哪个。

2. 压缩算法怎么选:gzip、zstd、lz4 的迁移实测取舍

2.1 先搞清楚"压缩比"在数据库数据上到底有多高

压缩效果和数据类型关系很大。MySQL逻辑备份出来的内容绝大多数是INSERT语句,字段名重复率高、数值和字符串也有大量重复模式,这类文本的压缩比往往能达到3:1甚至更高。物理备份则不一样,InnoDB的物理文件里包含已分配但未使用的页、页内碎片,压缩比通常不如SQL文本那么稳定,但依然有明显收益。

我自己的测试数据集一般取实际业务库的一个中间表集合,大约8GB,包含订单、用户、日志三类表。这样测出来的压缩比相对有代表性,也能看出不同算法在真实数据上的表现差异。如果手头没有现成数据集,建议先用mysqldump导一小部分真实数据压一下看效果,千万别拿全0的测试文件来评估压缩比,那是自欺欺人。

2.2 gzip:工具链成熟,但千万别顺手就上 -9

gzip 是大多数人最先想到的方案,因为mysqldump加gzip的组合几乎不需要额外安装任何东西:

mysqldump --single-transaction --set-gtid-purged=OFF -A | gzip -1 > dump.sql.gz

但这里有个非常容易踩的坑:有人习惯性用 gzip -9 追求最高压缩率,结果发现压缩速度直线下降,整个迁移的瓶颈从网络变成了CPU。跨地区迁移场景下,压缩率稍微低一点没关系,压缩速度太慢才是大问题。

实测里 gzip -1 比 -9 的压缩速度能快好几倍,压缩率只差10%左右。如果机器有多核,还可以用 pigz 并行压缩:

mysqldump --single-transaction -A | pigz -p 8 > dump.sql.gz

2.3 zstd:跨地区迁移场景里最推荐的主流选择

zstd是Facebook开源的压缩算法,如今在备份传输领域基本成了默认选项。它的特点是压缩率和gzip高层级差不多,但压缩速度快得多。用zstd处理8GB的SQL导出数据,默认级别下压缩吞吐能达到gzip -6的两倍以上,压缩比还略高。

我目前最常用的组合是这样:

mysqldump --single-transaction --set-gtid-purged=OFF -A | zstd -3 -T0 > dump.sql.zst

恢复时对应:

zstd -dc dump.sql.zst | mysql

这里的 -3 是压缩级别,-T0 表示自动使用所有CPU核心。如果你对压缩率有更高要求,可以调到 -9 甚至更高,但跨地区场景下我一般推荐 -3 到 -6 之间,平衡性最好。zstd还自带一个好处:解压速度也快,目标端恢复时可以更快地进入导入阶段。

2.4 lz4:带宽不紧张的"快"选项

lz4 是极致追求压缩速度的算法,压缩吞吐可以达到gzip的5倍以上,但压缩比一般只有2:1左右。什么场景适合用它?两地之间有高速专线、带宽不是瓶颈,反而是源库CPU压力大、不想让压缩占用太多计算资源的时候,用lz4边压缩边传,总体时间可能最短。

我给出一个参考表,注意具体数值会随机器配置和数据特征变化:

压缩算法常见级别压缩比参考压缩吞吐参考适合场景
gzip-12.5~3.0:1约100~150MB/s工具链要求高、只求稳
gzip-63.0~3.5:1约60~100MB/s日常默认,速度一般
zstd-32.8~3.5:1约200~350MB/s跨地区带宽有限时最推荐
zstd-93.2~4.0:1约100~150MB/s带宽极窄但CPU有富余
lz4-11.8~2.5:1约600MB/s以上高速专线+源库CPU吃紧

从表格可以看出,zstd在压缩率和压缩速度的平衡上确实最适合跨地区迁移。如果拿不准用哪个,直接上zstd -3基本不会错。

2.5 物理备份的压缩路径跟逻辑备份不一样

逻辑备份虽然通用,但大库导出导入非常耗时。跨地区迁移大库时,很多人改用Percona XtraBackup做物理备份,备份过程中就可以直接压缩:

xtrabackup --backup --compress=zstd --compress-threads=4 --target-dir=/data/backup

备份出来的压缩文件需要先解压再恢复,不能直接当数据目录用:

xtrabackup --decompress --target-dir=/data/backup xtrabackup --prepare --target-dir=/data/backup

物理备份的压缩有两个好处:一是备份阶段就压缩,传输前已经是压缩态;二是备份文件是原始数据页,恢复时不需要执行上千万条INSERT,导入速度快得多。代价是工具链更复杂,准备和校验的时间也要留足。

2.6 压缩过程中尽量用管道,避免"先压缩再传"的中间环节

我见过不少人把迁移做成了三步:先mysqldump导出原始文件,再gzip压缩,最后传文件。这样磁盘占用是原始加压缩两份,中间还多了两次全量读写,对时间和磁盘都是浪费。

正确做法是让数据"流"起来:

mysqldump --single-transaction -A | zstd -3 | ssh target 'cat > /data/dump.sql.zst'

或者用netcat在目标端直接收流:

mysqldump --single-transaction -A | zstd -3 | nc 目标IP 9000

这种方式能减少本地磁盘占用,也能避免二次读写消耗。缺点是如果传输中断,想要断点续传就麻烦,所以如果是跨公网长传,我更推荐后面会说到的rsync方案。

3. 限速不是拖后腿:业务与迁移共享链路的正确姿势

3.1 为什么必须做带宽限制

跨地区迁移时,很多时候业务流量和迁移流量走的是同一条公网出口,或者共用了同一条专线。如果不加限制直接全速传输,很容易把出口带宽占满,线上应用响应变慢,监控告警半夜响个不停,最后被迫中断迁移。所以限速的本质不是让迁移变慢,而是给迁移排一个合理的优先级:白天业务高峰时段压低迁移带宽,夜间窗口放开提速。

真正常见的做法绝不是"全速或者全停"两个极端,而是阶段式限速。比如白天限10Mbps,夜里放开到50Mbps,切换当天再给更高的临时额度。

3.2 rsync 的 bwlimit 参数,先把单位搞清楚

rsync是跨服务器传输文件的经典工具,优势是支持断点续传、增量同步,配合SSH还能加密传输。它的限速参数是 --bwlimit:

rsync -avP --bwlimit=4096 ./backup/ user@目标IP:/data/backup/

这个参数踩坑率极高:--bwlimit 的单位是 KB/s,不是 Mb/s。--bwlimit=4096 表示限速到 4096KB/s,约4MB/s。很多人以为是4096Mbps,结果发现速度完全对不上。如果想把带宽限制在50Mbps,需要算成 50×1024÷8≈6400KB/s。

要注意的是,如果已经用zstd对数据做过外部压缩,rsync的 -z 参数就别再开了,否则等于对已经压缩过的文件再做一次压缩,白白消耗CPU。

3.3 用 tc 做更精细的流量整形

如果觉得rsync只能限制单个进程不够用,可以用Linux自带的tc命令做流量整形,精确到整个网卡或者某个目标IP。比如把eth0整个出口限到20Mbit:

tc qdisc add dev eth0 root tbf rate 20mbit burst 32kbit latency 400ms

更精细的场景是源库主机上同时跑着多个迁移任务,只限制发往目标IP的流量:

tc qdisc add dev eth0 root handle 1: htb default 10 tc class add dev eth0 parent 1: classid 1:10 htb rate 20mbit tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dst 目标IP flowid 1:10

tc的优点是很灵活,缺点也明显:命令是即时生效的,网络服务重启或者机器重启后配置会自动消失,需要固化到systemd服务或初始化脚本里。如果团队里网络功底一般,还是优先用工具自带的限速参数更省心。

3.4 分时段提速,比固定限速更实用

迁移窗口通常集中在深夜,所以分时段限速比固定限速实用得多。我一般用cron定时调整tc参数:

0 23 * * * tc qdisc change dev eth0 root tbf rate 50mbit burst 64kbit latency 400ms 0 6 * * * tc qdisc change dev eth0 root tbf rate 10mbit burst 64kbit latency 400ms

如果你是云服务器,也可以直接利用云厂商的带宽管理功能或安全组限速策略,底层逻辑是一样的。反正目的就是在不影响业务的前提下,尽可能挤时间传输数据。

3.5 并发数必须跟着带宽上限走

很多人看到"多线程迁移"就直接把并发开到8个、16个,结果总吞吐超过链路容量,拥塞和重传反而拖慢了整体进度。正确做法是先测单流实际吞吐,再根据限速目标推算并发数:

并行度 ≈ 限速目标值 ÷ 单流实际吞吐

比如限制在50Mbps,单流稳定6MB/s,那么开2到4个并发就能打满余量,开8个只会徒增确认包和重传。这个原则在mysqldump多线程、mydumper、rsync多进程、XtraBackup并行流传输里都适用。

4. 压缩和限速之外,跨地区迁移实战里的隐藏提速点

4.1 导出别只用 mysqldump 单线程

mysqldump很好用,但它导出大库时是单线程,一条一条SELECT出来写文件,速度确实有限。如果库里有几千张表或者几张大表,导出环节就会拖后腿,这时候可以换成mydumper。

mydumper可以把表拆成多个chunk,多线程并行导出,并把每张表单独存成一个文件,方便按优先级传输和导入。导出时也可以配合压缩:

mydumper -u root -p xxx -B bizdb --threads=8 --compress -o /data/backup

导入端用对应的myloader并行导入。要注意的是,并行度不是越高越好,导入端的目标库连接数上限、磁盘IO能力都要考虑进去,否则导入端本身会被压垮。

4.2 别让目标端导入变成新瓶颈

很多次排查下来,发现网络传输已经跑到计划值了,但目标端导入速度跟不上,整个迁移卡在"解压快、导入慢"的状态。这时候优先检查目标库的几个关键参数:

  • innodb_buffer_pool_size 是否够大,最好能装下常用索引和热点数据
  • 导入期间可以临时把 innodb_flush_log_at_trx_commit 设为0、sync_binlog设为0,减少磁盘同步次数,但注意导入完成后必须改回安全值
  • 如果目标库还挂着级联复制,先暂停从库的SQL线程,或者调整并行复制线程数,避免导入抖动影响其他链路

大表导入还有一个常用技巧:先只建表结构,不建二级索引,数据导入完成后再批量创建索引。因为每插入一行数据都要同步维护索引,代价非常高,先传数据后建索引往往能快出好几倍。

4.3 增量同步:让停机窗口无限缩短

如果数据量太大,一次全量迁移想在一个窗口内完成根本不现实。这时候必须采用"全量+增量"的两阶段方案:

  1. 全量备份:用XtraBackup或mysqldump做全量备份,压缩传输到目标端
  2. 增量同步:源库开启binlog,并且格式设为ROW模式,用mysqlbinlog把新增的binlog持续同步到目标端
mysqlbinlog --read-from-remote-server --host=源库IP --user=repl --password=xxx \ --stop-never mysql-bin.000001 | mysql -h 目标库IP

切换前对比binlog位点,确认目标库追平所有增量,然后短暂停写、切换、验证。这种方式能把实际不可用时间压缩到几分钟,代价是binlog传输本身也要占带宽,限速策略要把这部分流量一起算进去。

4.4 校验和断点:迁移最容易忽略的隐形时间成本

跨地区长传最怕两件事:传了一半断了,以及传完了发现数据不一致。rsync的 -P 参数可以在中断后继续传输,所以我很推荐用它来传备份文件。但如果用nc、socat这类裸流工具,中断就基本要重来,所以裸流只建议在内网或短链路场景用。

数据校验方面,pt-table-checksum是主流选择,它会在源库和目标库分别计算校验值再比对。但要注意它会扫描全表,对线上业务有压力,建议放在低峰期执行。如果时间紧张,至少也要抽几张关键表做行数和最大值、最小值的快速比对。

4.5 压缩与加密同时做,不要为了安全丢掉性能

跨地区公网传输时,敏感数据不能明文裸奔。用SSH通道或者TLS加密是必须的。很多人担心加密会影响传输速度,实际上现代CPU都支持AES-NI指令集,加密带来的性能损耗很小。比如rsync走SSH时可以指定加密算法:

rsync -avP -e 'ssh -c aes128-gcm@openssh.com' --bwlimit=6400 \ ./backup/ user@目标IP:/data/backup/

如果嫌麻烦,直接默认SSH通道也没问题,别因为格式问题放弃加密。安全性永远值得那一点点性能损耗。

4.6 先演练一次小规模迁移

最后说一个我自己吃了不少亏才养成的习惯:大规模迁移前,先拿一个几GB的代表性子集走一遍完整流程,包括压缩、限速、传输、解压、导入、校验。这一步能验证所有命令参数是否合理,还能给你一个真实的"每秒多少MB"的基准值,用这个值去推算总时长,误差会小很多。

演练时重点观察目标端的CPU使用率和磁盘IO,如果解压导入阶段CPU已经飙到90%以上,说明网络传输不是瓶颈,目标端才是,后面正式迁移时要考虑加大目标端规格或者调整导入参数。实际跨地区项目里,很多问题不是参数不会配,而是没提前在目标端环境验证过解压和导入速度。一个几GB的演练,能帮你避免正式迁移时凌晨三点才发现跑不完的尴尬。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询