取名mypumpkin,是python封裝的一個讓mysqldump以多線程的方式導出庫表,再以mysql命令多線程導入新庫,用於成倍加快導出,特別是導入的速度。這一切只須要在 mysqldump 或 mysql 命令前面加上 mypumpkin.py
便可,因此稱做魔法。python
項目地址:https://github.com/seanlook/m... mysql
該程序源於須要對現網單庫幾百G的數據進行轉移到新庫,並對中間進行一些特殊操做(如字符集轉換),沒法容忍mysqldump導入速度。有人可能會提到爲何不用 mydumper,其實也嘗試過它但仍是放棄了,緣由有:git
不能設置字符集
mydumper強制使用 binary 方式來鏈接庫以達到不關心備份恢復時的字符集問題,然而個人場景下須要特地以不一樣的字符集導出、再導入。寫這個程序的時候正好在公衆號看到網易有推送的一篇文章 (解密網易MySQL實例遷移高效完成背後的黑科技),提到他們對mydumper的改進已支持字符集設置,但是在0.9.1版本的patch裏仍是沒找到。github
沒有像 mysqldump 那樣靈活控制過濾選項(導哪些表、忽略哪些表)
由於數據量之巨大,並且將近70%是不變動的歷史表數據,這些表是能夠提早導出轉換的;又有少許單表大於50G的,最好是分庫導出轉換。mydumper 不具有 mysqldump 這樣的靈活性sql
對忽略導出gtid信息、觸發器等其它支持
阿里雲rds 5.6 導出必需要設置 set-gtid-purged=OFFshell
另外有人還可能提到 mysqlpump —— 它纔是我認爲mysqldump應該具備的模樣,語法兼容,基於表的併發導出。可是隻有 mysql服務端 5.7.9 以上才支持,這就是現實和理想的距離。。。網絡
首先說明,mysqldump的導出速度並不慢,經測試能達到50M/s的速度,10G數據花費3分鐘的樣子,能夠看到瓶頸在於網絡和磁盤IO,再怎樣的導出工具也快不了多少,可是導入卻花了60分鐘,磁盤和網絡大概只用到了20%,瓶頸在目標庫寫入速度(而通常順序寫入達不到IOPS限制),因此mypumpkin就誕生了 —— 兼顧myloader的導入速度和mysqldump導出的靈活性。多線程
<!-- more -->併發
用python構造1個隊列,將須要導出的全部表一次放到隊列中,同時啓動N個python線程,各自從這個Queue裏取出表名,subprocess調用操做系統的mysqldump命令,導出數據到以 dbname.tablename.sql 命名的文件中。load in 與 dump out 相似,根據指定的庫名或表名,從dump_dir目錄找到全部sql文件,壓進隊列,N個線程同時調用mysql構造新的命令,模擬 <
操做。ide
參數解析從原來本身解析,到改用argparse模塊,幾乎作了一次重構。
對於沒有指定--tables
的狀況,程序會主動去庫裏查詢一下全部表名,而後過濾進隊列。
load in目標庫,選項作到與dump out同樣豐富,能夠指定導入哪些db、哪些表、忽略哪些表。
其中的重點是作到與原mysqldump兼容,由於須要對與表有關的選項(-B
, -A
, --tables
, --ignore=
),進行分析並組合成新的執行命令,考慮的異常狀況很是多。
重要:導出的數據不保證庫級別的一致性
對歷史不變表,是不影響的
具體到一個表能保證一致性,這是mysqldump自己採用哪些選項決定的
不一樣表導出動做在不一樣的mysqldump命令中,沒法保證事務。
在個人案例場景下,是有開發同窗輔助使用一套binlog解析程序,等完成後重放全部變動,來保證最終一致性。
另,許多狀況下咱們導數據,並不須要完整的或者一致的數據,只是用於離線分析或臨時導出,重點是快速拿數據給到開發。
不尋常選項識別
程序已經盡力作到與mysqldump命令兼容,只須要加上 mypumpkin.py、指定dump-dir,就完成併發魔法,但有些狀況的參數不方便解析,暫不支持格式:
db1 table1 table2 db2 db3
即以上沒法在命令行下判斷 db一、table1 是庫名仍是表面,用的時候只需記住「[-A|-B], [--tables], [--ignore-table]」三組,必須出現一個:db1 table1 table2
改爲db1 --tables table1 table2
,db2
改爲-B db2 db3
。
密碼暫只能顯式輸入
安裝基於python 2.7 開發,其它版本沒測。須要按 MySQLdb 庫。
./mypumpkin.py --help Only mysqldump or mysql allowed after mypumpkin.py usage: mypumpkin.py {mysqldump|mysqls} [--help] This's a program that wrap mysqldump/mysql to make them dump-out/load-in concurrently. Attention: it can not keep consistent for whole database(s). optional arguments: --help show this help message and exit -B db1 [db1 ...], --databases db1 [db1 ...] Dump one or more databases -A, --all-databases Dump all databases --tables t1 [t1 ...] Specifiy tables to dump. Override --databases (-B) --ignore-table db1.table1 [db1.table1 ...] Do not dump the specified table. (format like --ignore-table=dbname.tablename). Use the directive multiple times for more than one table to ignore. --threads =N Threads to dump out [2], or load in [CPUs*2]. --dump-dir DUMP_DIR Required. Directory to dump out (create if not exist), Or Where to load in sqlfile At least one of these 3 group options given: [-A,-B] [--tables] [--ignore-table]
--dump-dir
,必選項,原來用的shell標準輸入輸出 > or <
不容許使用。dump-dir指定目錄不存在時會嘗試自動建立。
--threads=N
,N指定併發導出或導入線程數。dump out 默認線程數2, mypumpkin load in 默認線程數是 cpu個數 * 2。
注:線程數不是越大越好,這裏主要的衡量指標是網絡帶寬、磁盤IO、目標庫IOPS,最好用 dstat 觀察一下。
-B
, --tables
,--ignore-table
,使用與mysqldump相同,如:
在mysqldump裏面,--tables
會覆蓋--databases/-B
選項
在mysqldump裏面,--tables
與--ignore-table
不能同時出現
在mysqldump裏面,若是沒有指定-B
,則--tables
或--ignore-table
必須緊跟db名以後
其它選項,mypumpkin會原封不動的保留下來,放到shell去執行。因此若是其它選項有錯誤,檢查是交給原生mysqldump去作的,執行過程遇到一個失敗則會退出線程。
導出:
## 導出源庫全部db到visit_dumpdir2目錄 (不包括information_schema和performance_schema) $ ./mypumpkin.py mysqldump -h dbhost_name -utest_user -pyourpassword -P3306 \ --single-transaction --opt -A --dump-dir visit_dumpdir2 ## 導出源庫db1,db2,會從原庫查詢全部表名來過濾 $ ./mypumpkin.py mysqldump -h dbhost_name -utest_user -pyourpassword -P3306 \ --single-transaction --opt -B db1 db2 --dump-dir visit_dumpdir2 ## 只導出db1庫的t1,t2表,若是指定表不存在則有提示 $ ./mypumpkin.py mysqldump -h dbhost_name -utest_user -pyourpassword -P3306 \ --single-transaction --opt -B db1 --tables t1 t2 --dump-dir visit_dumpdir2 ## 導出db1,db2庫,但忽略 db1.t1, db2.t2, db2.t3表 ## mysqldump只支持--ignore-table=db1.t1這種,使用多個重複指令來指定多表。這裏作了兼容擴展 $ ./mypumpkin.py mysqldump -h dbhost_name -utest_user -pyourpassword --single-transaction \ --opt -B db1 db2 --ignore-table=db1.t1 --ignore-table db2.t2 db2.t3 --dump-dir visit_dumpdir2 (若是-A表示所有db) ## 不帶 -A/-B $ ./mypumpkin.py mysqldump -h dbhost_name -utest_user -pyourpassword -P3306 \ --single-transaction --opt db1 --ignore-table=db1.t1 --dump-dir=visit_dumpdir2 ## 其它選項不作處理 $ ./mypumpkin.py mysqldump -h dbhost_name -utest_user -pyourpassword -P3306 \ --single-transaction --set-gtid-purged=OFF --no-set-names --skip-add-locks -e -q -t -n --skip-triggers \ --max-allowed-packet=134217728 --net-buffer-length=1638400 --default-character-set=latin1 \ --insert-ignore --hex-blob --no-autocommit \ db1 --tables t1 --dump-dir visit_dumpdir2
導入: -A
, -B
, --tables
, --ignore-table
, --threads
, --dump-dir
用法與做用與上面徹底相同,舉部分例子:
## 導入dump-dir目錄下全部表 $ ./mypumpkin.py mysql -h dbhost_name -utest_user -pyourpassword --port 3307 -A \ --dump-dir=visit_dumpdir2 ## 導入db1庫(全部表) $ ./mypumpkin.py mysql -h dbhost_name -utest_user -pyourpassword --port 3307 -B db1 \ --dump-dir=visit_dumpdir2 ## 只導入db.t1表 $ ./mypumpkin.py mysql -h dbhost_name -utest_user -pyourpassword --port 3307 \ --default-character-set=utf8mb4 --max-allowed-packet=134217728 --net-buffer-length=1638400 \ -B db1 --tables t1 --dump-dir=visit_dumpdir2 ## 導入db1,db2庫,但忽略db1.t1表(會到dump-dir目錄檢查db1,db2有無對應的表存在,不在目標庫檢查) $ ./mypumpkin.py mysql -h dbhost_name -utest_user -pyourpassword --port 3307 \ -B db1 db2 --ignore-table=db1.t1 --dump-dir=visit_dumpdir2