首先說明,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構造新的命令,模擬?
參數解析從原來自己解析,到改用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
即以上無法在命令行下判斷 db1、table1 是庫名還是表面,用的時候只需記住“[-A|-B], [–tables], [–ignore-table]”三組,必須出現一個:db1 table1 table2改成db1 –tables table1 table2,db2改成-B db2 db3。
密碼暫只能顯式輸入
4. 使用說明
安裝基于python 2.7 開發,其它版本沒測。需要按 MySQLdb 庫。
4.1 help
./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
–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去做的,執行過程遇到一個失敗則會退出線程。
4.2 example
導出:
##?導出源庫所有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