迁移 TB 级 MySQL 实战
前期准备
公司打算把放在 AWS RDS 上的数据迁移到 GCP 的 CloudSQL 上去。目前我们再 AWS RDS 上的数据有超过 4TB 的数据,用常规的方法还是比较吃力的。
之前调研了一下 google 提供的迁移工具 DMS,但是这个工具像个玩具一言难尽,我觉得从性能和好用来说远远比不上之前我是用过的 aliyun 的 DTS. 在正常的情况下只能保证 3MiB/s 左右的速度,对于我们的数据量来说简直是小水管。光导一次数据就需要一周的时间。由于 AWS 上的 binlog 最多只提供 7 天的存储,所以大于 7 天的方案我们是无法使用的。
之后我也尝试了一下 pxb,和 mysqldump。pxb 是因为不支持 AWS RDS 而放弃,而 mysqldump 是因为它的性能不行遂放弃。
最终我把目光放到了和 pxb 一样同属 percona 的另外一款工具上 mydumper。
所以最终我敲定了如下流程:
流程中
1. 首先将 mydumper 下载和部署到处理这个任务的 gcp 机器上。
Ubuntu
sudo apt-get install cmake g++ git sudo apt-get install libglib2.0-dev zlib1g-dev libpcre3-dev libssl-dev sudo apt-get install libmysqlclient-dev sudo apt-get install libatomic1 sudo wget https://github.com/maxbube/mydumper/releases/download/v0.10.7-2/mydumper_0.10.7-2.focal_amd64.deb sudo dpkg -i mydumper_0.10.7-2.focal_amd64.deb
弄完之后我们就已经可以在机器上使用 mydumper 和 myloader 了。
2. 接下来我们将 AWS RDS 里面的数据拷贝到现在 gcp 机器的某个目录下面(需要确保磁盘足够大,也要确保 iops 性能网络带宽 CPU 还有内存等 这会严重决定你的迁移速度)
mydumper -h <hostname> -p <password> -u <uusername> -o <target-path> --lock-all-tables --chunk-filesize 2048 --events --routines --triggers
这里有个参数特别值得说一下就是 chunk-filesize,chunk-filesize 这个参数会决定当单个文件到多大之后来对文件进行切割,单位是 M. 切割文件会影响什么呢,最后会影响到 myloader 执行的速度。
因为最后 myloader 的步骤是可以使用多线程执行的,到时候可能会面临一个 u 对应一个文件的情况。如果你都是大文件,到时候再 loader 的时候就无法使用多线程来加快导入的速度,你可能会非常的痛苦。但是另一方面,如果你有严重的数据偏移情况,
可能同样会面临单个表的最大写入瓶颈,这是一个经验值,我个人试了一天的参数,觉得如果你有上百g 的大表,不要将该切割大小改得小于 50GB。 当然你可以根据你的实际情况来设置这个参数,因为目标数据库性能,和跑该脚本的机器都会对性能有所影响。
另外不得不 highlight 一下,这个参数如果设置得太小则会严重影响 dump 的效率,所以建议大家多试几个参数,找到一个合适的参数再开始跑全量会让你事半功倍。
还值得注意的一点的是,如果你的表有非常严重的数据偏移,比如有些表巨大,那可能需要将查询时间的参数暂时调大,不然可能会在拉取数据的过程中超时。
max_execution_time=86400000
我暂时将最大查询时间设置到了 24 小时,接下来就是漫长的等待了和监控流程了。
3. 等了很久数据终于被导到了目标机器,现在需要执行 myloader 将数据导进目标数据库。
myloader --host=<hostname> --user=<username> --password=<password> --directory=<dir> --queries-per-transaction=50000 --threads=85 --compress-protocol --verbose=3 -e
--disable-redo-log --innodb-optimize-keys
不得不说 loader 要比想象中更复杂更曲折。这次我的迁移既有严重的数据偏移的情况,总量大小也比较大,单表最大超过800g 总量超过4T. 所以在 loader 的时候我们必须动用一切可以使用的方法让单纯的插入可以达到极限速度。
经过反复的测试,在数据库侧影响 MySQL 插入比较核心的就是 cpu 核心数还有磁盘的 io 。在迁移的时候我将 CloudSQL 开至 32核 64gb 磁盘使用 ssd 有 25000iops。以便让我在 load 的时候开满性能。
其他还需要注意的是,myloader 有几个非常影响插入效率的参数我们必须设置。
1. queries-per-transaction 在数据库性能要保证的情况下,我们可以使用尽量大一点的单个事务大小 这里我设置的 50000.
2. threads 这里的每个 threads 都可以同时读取上面 dump 时候所 chuck 的文件。我使用了一个 32 核心的机器来做这次数据迁移。所以瓶颈不会在 gcp vm 上,取决于数据库。我这里尝试了一下开到80+个 可以有效利用 CloudSQL 的所有 cpu 资源。
3. disable-redo-log 在最新的 0.10.7 版上的新功能,单纯的数据迁移一定要使用的参数,可以帮我们直接禁用 redo log 的写入进一步提升写入性能20%-25%。这个 feture 的灵感来自
As of MySQL 8.0.21, you can disable redo logging using the ALTER INSTANCE DISABLE INNODB REDO_LOG statement. This functionality is intended for loading data into a new MySQL instance. Disabling redo logging speeds up data loading by avoiding redo log writes and doublewrite buffering.
4. innodb-optimize-keys 提升插入性能的终极大招,这个特性可以将只创建带主键的表,等待所有数据插入结束之后再在目标数据库上建立二级索引和约束。可以在超大规模数据上有绝对的性能效果。在 reference 中有一篇与他相关的文章,有兴趣可以看看。
一切设置好,接下来就又是漫长的等待。。。。。。
4. 数据终于导入进去之后,我们去之前那台被停下来的 AWS RDS replica 查看当前 binlog 位置
show master status
并将位置作为CloudSQL 的源头。然后将 AWS RDS replica 重新拉起来去跟上 master。
同样的 CloudSQL 也将 RDS replica 作为 master 开始追赶 binlog 位置即可。
总结
总的来说,一切的瓶颈还是在机器性能和网络带宽上。面对大数据量的迁移,网络带宽对于时间的 影响基本上起了决定性的作用。我们只能通过并发工具,还有其他调优来尽量减少这个时间。
以上。
下面贴一个在 CloudSQL 上迁移的时候使用的配置:
innodb_online_alter_log_max_size = 1073741824 max_execution_time = 86399999 innodb_write_io_threads = 16 innodb_read_io_threads = 16 sql_mode = NO_ENGINE_SUBSTITUTION performance_schema = on
Reference:
https://www.percona.com/blog/tag/mydumper/ Percona Tag - mydumper
https://github.com/maxbube/mydumper/tree/v0.10.7-2 mysqldumper
https://www.percona.com/blog/2015/01/21/importing-big-tables-large-indexes-myloader/ Importing big tables with large indexes with Myloader MySQL tool
https://medium.com/tensult/mydumper-myloader-and-my-experience-of-migrating-to-aws-rds-ff74fc9c1add MyDumper, MyLoader and My Experience of migrating to AWS RDS
https://severalnines.com/database-blog/mysql-cloud-online-migration-amazon-rds-your-own-server-part2 MySQL in the Cloud - Online Migration from Amazon RDS to Your own Server: Part2
https://cloud.google.com/sql/docs/mysql/replication/configure-external-replica 配置外部副本
https://www.youtube.com/watch?v=77JMe-EHIU8 Best Practices for Migrating to Cloud SQL for MySQL (Cloud Next '18)
https://cloud.google.com/blog/products/databases/how-broadcom-migrated-to-google-cloud-sql Continuous migration to Cloud SQL for terabyte-scale databases with minimal downtime