天天看点

让mysqldump变成并发导出导入的魔法

取名mypumpkin,是python封装的一个让mysqldump以多线程的方式导出库表,再以mysql命令多线程导入新库,用于成倍加快导出,特别是导入的速度。这一切只需要在 mysqldump 或 mysql 命令前面加上 <code>mypumpkin.py</code> 即可,所以称作魔法。

该程序源于需要对现网单库几百g的数据进行转移到新库,并对中间进行一些特殊操作(如字符集转换),无法容忍mysqldump导入速度。有人可能会提到为什么不用 mydumper,其实也尝试过它但还是放弃了,原因有:

不能设置字符集

没有像 mysqldump 那样灵活控制过滤选项(导哪些表、忽略哪些表)

因为数据量之巨大,而且将近70%是不变更的历史表数据,这些表是可以提前导出转换的;又有少量单表大于50g的,最好是分库导出转换。mydumper 不具备 mysqldump 这样的灵活性

对忽略导出gtid信息、触发器等其它支持

阿里云rds 5.6 导出必须要设置 set-gtid-purged=off

另外有人还可能提到 mysqlpump —— 它才是我认为mysqldump应该具有的模样,语法兼容,基于表的并发导出。但是只有 mysql服务端 5.7.9 以上才支持,这就是现实和理想的距离。。。

首先说明,mysqldump的导出速度并不慢,经测试能达到50m/s的速度,10g数据花费3分钟的样子,可以看到瓶颈在于网络和磁盘io,再怎样的导出工具也快不了多少,但是导入却花了60分钟,磁盘和网络大概只用到了20%,瓶颈在目标库写入速度(而一般顺序写入达不到iops限制),所以mypumpkin就诞生了 —— 兼顾myloader的导入速度和mysqldump导出的灵活性。

用python构造1个队列,将需要导出的所有表一次放到队列中,同时启动n个python线程,各自从这个queue里取出表名,subprocess调用操作系统的mysqldump命令,导出数据到以 dbname.tablename.sql 命名的文件中。load in 与 dump out 类似,根据指定的库名或表名,从dump_dir目录找到所有sql文件,压进队列,n个线程同时调用mysql构造新的命令,模拟 <code>&lt;</code> 操作。

参数解析从原来自己解析,到改用argparse模块,几乎做了一次重构。

对于没有指定<code>--tables</code>的情况,程序会主动去库里查询一下所有表名,然后过滤进队列。

load in目标库,选项做到与dump out一样丰富,可以指定导入哪些db、哪些表、忽略哪些表。

其中的重点是做到与原mysqldump兼容,因为需要对与表有关的选项(<code>-b</code>, <code>-a</code>, <code>--tables</code>, <code>--ignore=</code>),进行分析并组合成新的执行命令,考虑的异常情况非常多。

重要:导出的数据不保证库级别的一致性

对历史不变表,是不影响的

具体到一个表能保证一致性,这是mysqldump本身采用哪些选项决定的

不同表导出动作在不同的mysqldump命令中,无法保证事务。

在我的案例场景下,是有开发同学辅助使用一套binlog解析程序,等完成后重放所有变更,来保证最终一致性。

另,许多情况下我们导数据,并不需要完整的或者一致的数据,只是用于离线分析或临时导出,重点是快速拿数据给到开发。

不寻常选项识别

程序已经尽力做到与mysqldump命令兼容,只需要加上 mypumpkin.py、指定dump-dir,就完成并发魔法,但有些情况的参数不方便解析,暂不支持格式:

即以上无法在命令行下判断 db1、table1 是库名还是表面,用的时候只需记住“[-a|-b], [--tables], [--ignore-table]”三组,必须出现一个:<code>db1 table1 table2</code>改成<code>db1 --tables table1 table2</code>,<code>db2</code>改成<code>-b db2 db3</code>。

密码暂只能显式输入

安装基于python 2.7 开发,其它版本没测。需要按 mysqldb 库。

<code>--dump-dir</code>,必选项,原来用的shell标准输入输出 <code>&gt; or &lt;</code> 不允许使用。dump-dir指定目录不存在时会尝试自动创建。

<code>--threads=n</code>,n指定并发导出或导入线程数。dump out 默认线程数2, mypumpkin load in 默认线程数是 cpu个数 * 2。

注:线程数不是越大越好,这里主要的衡量指标是网络带宽、磁盘io、目标库iops,最好用 dstat 观察一下。

<code>-b</code>, <code>--tables</code>,<code>--ignore-table</code>,使用与mysqldump相同,如:

在mysqldump里面,<code>--tables</code>会覆盖<code>--databases/-b</code>选项

在mysqldump里面,<code>--tables</code>与<code>--ignore-table</code>不能同时出现

在mysqldump里面,如果没有指定<code>-b</code>,则<code>--tables</code>或<code>--ignore-table</code>必须紧跟db名之后

其它选项,mypumpkin会原封不动的保留下来,放到shell去执行。所以如果其它选项有错误,检查是交给原生mysqldump去做的,执行过程遇到一个失败则会退出线程。

导出:

导入:

<code>-a</code>, <code>-b</code>, <code>--tables</code>, <code>--ignore-table</code>, <code>--threads</code>, <code>--dump-dir</code>用法与作用与上面完全相同,举部分例子: