首頁  >  文章  >  資料庫  >  讓mysqldump變成並發導出導入的魔法

讓mysqldump變成並發導出導入的魔法

高洛峰
高洛峰原創
2016-11-21 15:18:581585瀏覽

首先說明,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


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn