做者簡介:
楊奇龍,網名「北在南方」,7年DBA老兵,目前任職於杭州有贊科技DBA,主要負責數據庫架構設計和運維平臺開發工做,擅長數據庫性能調優、故障診斷。
做爲 MySQL DBA,相信咱們你們都會對大表變動(大於10G 以上的)比較頭疼,尤爲是某些 DDL 會鎖表,影響業務可持續性。目前通用的方案使用 Percona 公司開源的 pt-osc 工具解決致使鎖表的操做,還有一款 github 基於 go 語言開發的 gh-ost。本文主要介紹 gh-ost 使用方法,其工做原理放到下一篇文章介紹。html
gh-ost 做爲一個假裝的備庫,能夠從主庫/備庫上拉取 binlog,過濾以後從新應用到主庫上去,至關於主庫上的增量操做經過 binlog 又應用回主庫自己,不過是應用在幽靈表上。
git
其大體的工做過程:github
固然 gh-ost 也會作不少前置的校驗檢查,好比 binlog_format,表的主鍵和惟一鍵,是否有外鍵等等
這種架構帶來諸多好處,例如:算法
整個流程異步執行,對於源表的增量數據操做沒有額外的開銷,高峯期變動業務對性能影響小。
下降寫壓力,觸發器操做都在一個事務內,gh-ost 應用 binlog 是另一個鏈接在作。
可中止,binlog 有位點記錄,若是變動過程發現主庫性能受影響,能夠馬上中止拉binlog,中止應用 binlog,穩定以後繼續應用。
可測試,gh-ost 提供了測試功能,能夠鏈接到一個備庫上直接作 Online DDL,在備庫上觀察變動結果是否正確,再對主庫操做,內心更有底。不過不推薦在備庫直接操做。
a. 鏈接到從庫,在主庫作遷移
這是 gh-ost 默認的工做方式。gh-ost 將會檢查從庫狀態,找到集羣結構中的主庫並鏈接,接下來進行遷移操做:數據庫
若是你的主庫的日誌格式是 SBR,工具也能夠正常工做。但從庫必須啓用二級制日誌( log_bin,log_slave_updates) 而且設置 binlog_format=ROW 。segmentfault
b. 鏈接到主庫
直接鏈接到主庫構造 slave,在主庫上進行 copy 數據和應用 binlog,經過指定 --allow-on-master 參數便可。固然主庫的 binlog 模式必須是 row 模式。服務器
c. 在從庫遷移/測試
該模式會在從庫執行遷移操做。gh-ost 會簡單的鏈接到主庫,此後全部的操做都在從庫執行,不會對主庫進行任何的改動。整個操做過程當中,gh-ost 將控制速度保證從庫能夠及時的進行數據同步架構
--migrate-on-replica 表示 gh-ost 會直接在從庫上進行遷移操做。即便在複製運行階段也能夠進行表的切換操做。
--test-on-replica 表示 遷移操做只是爲了測試在切換以前複製會中止,而後會進行切換操做,而後在切換回來,你的原始表最終仍是原始表。兩個表都會保存下來,複製操做是中止的。你可>以對這兩個表進行一致性檢查等測試操做。
https://github.com/github/gh-ost
這裏列出比較重要的參數,你們能夠經過以下命令獲取比較詳細的參數以及其解釋。併發
gh-ost --help -allow-master-master: 是否容許gh-ost運行在雙主複製架構中,通常與-assume-master-host參數一塊兒使用 -allow-nullable-unique-key: 容許gh-ost在數據遷移依賴的惟一鍵能夠爲NULL,默認爲不容許爲NULL的惟一鍵。若是數據遷移(migrate)依賴的惟一鍵容許NULL值,則可能形成數據不正確,請謹慎使用。 -allow-on-master: 容許gh-ost直接運行在主庫上。默認gh-ost鏈接的從庫。 -alter string: DDL語句 -assume-master-host string: 爲gh-ost指定一個主庫,格式爲」ip:port」或者」hostname:port」。在這主主架構裏比較有用,或則在gh-ost發現不到主的時候有用。 -assume-rbr: 確認gh-ost鏈接的數據庫實例的binlog_format=ROW的狀況下,能夠指定-assume-rbr,這樣能夠禁止從庫上運行stop slave,start slave,執行gh-ost用戶也不須要SUPER權限。 -chunk-size int: 在每次迭代中處理的行數量(容許範圍:100-100000),默認值爲1000。 -concurrent-rowcount: 該參數若是爲True(默認值),則進行row-copy以後,估算統計行數(使用explain select count(*)方式),並調整ETA時間,不然,gh-ost首先預估統計行數,而後開始row-copy。 -conf string:gh-ost的配置文件路徑。 -critical-load string: 一系列逗號分隔的status-name=values組成,當MySQL中status超過對應的values,gh-ost將會退出。-critical-load Threads_connected=20,Connections=1500,指的是當MySQL中的狀態值Threads_connected>20,Connections>1500的時候,gh-ost將會因爲該數據庫嚴重負載而中止並退出。 -critical-load-hibernate-seconds int : 負載達到critical-load時,gh-ost在指定的時間內進入休眠狀態。它不會讀/寫任何來自任何服務器的任何內容。 -critical-load-interval-millis int: 當值爲0時,當達到-critical-load,gh-ost當即退出。當值不爲0時,當達到-critical-load,gh-ost會在-critical-load-interval-millis秒數後,再次進行檢查,再次檢查依舊達到-critical-load,gh-ost將會退出。 -cut-over string: 選擇cut-over類型: atomic/two-step,atomic(默認)類型的cut-over是github的算法,two-step採用的是facebook-OSC的算法。 -cut-over-exponential-backoff -cut-over-lock-timeout-seconds int: gh-ost在cut-over階段最大的鎖等待時間,當鎖超時時,gh-ost的cut-over將重試。(默認值:3) -database string: 數據庫名稱。 -default-retries int: 各類操做在panick前重試次數。(默認爲60) -dml-batch-size int: 在單個事務中應用DML事件的批量大小(範圍1-100)(默認值爲10) -exact-rowcount: 準確統計表行數(使用select count(*)的方式),獲得更準確的預估時間。 -execute: 實際執行alter&migrate表,默認爲noop,不執行,僅僅作測試並退出,若是想要ALTER TABLE語句真正落實到數據庫中去,須要明確指定-execute -exponential-backoff-max-interval int -force-named-cut-over: 若是爲true,則'unpostpone | cut-over'交互式命令必須命名遷移的表 -heartbeat-interval-millis int: gh-ost心跳頻率值,默認爲500 -initially-drop-ghost-table: gh-ost操做以前,檢查並刪除已經存在的ghost表。該參數不建議使用,請手動處理原來存在的ghost表。默認不啓用該參數,gh-ost直接退出操做。 -initially-drop-old-table: gh-ost操做以前,檢查並刪除已經存在的舊錶。該參數不建議使用,請手動處理原來存在的ghost表。默認不啓用該參數,gh-ost直接退出操做。 -initially-drop-socket-file: gh-ost強制刪除已經存在的socket文件。該參數不建議使用,可能會刪除一個正在運行的gh-ost程序,致使DDL失敗。 -max-lag-millis int: 主從複製最大延遲時間,當主從複製延遲時間超過該值後,gh-ost將採起節流(throttle)措施,默認值:1500s。 -max-load string: 逗號分隔狀態名稱=閾值,如:'Threads_running=100,Threads_connected=500'. When status exceeds threshold, app throttles writes -migrate-on-replica: gh-ost的數據遷移(migrate)運行在從庫上,而不是主庫上。 -nice-ratio float: 每次chunk時間段的休眠時間,範圍[0.0…100.0]。0:每一個chunk時間段不休眠,即一個chunk接着一個chunk執行;1:每row-copy 1毫秒,則另外休眠1毫秒;0.7:每row-copy 10毫秒,則另外休眠7毫秒。 -ok-to-drop-table: gh-ost操做結束後,刪除舊錶,默認狀態是不刪除舊錶,會存在_tablename_del表。 -panic-flag-file string: 當這個文件被建立,gh-ost將會當即退出。 -password string : MySQL密碼 -port int : MySQL端口,最好用從庫 -postpone-cut-over-flag-file string: 當這個文件存在的時候,gh-ost的cut-over階段將會被推遲,數據仍然在複製,直到該文件被刪除。 -skip-foreign-key-checks: 肯定你的表上沒有外鍵時,設置爲'true',而且但願跳過gh-ost驗證的時間-skip-renamed-columns ALTER -switch-to-rbr: 讓gh-ost自動將從庫的binlog_format轉換爲ROW格式。 -table string: 表名 -throttle-additional-flag-file string: 當該文件被建立後,gh-ost操做當即中止。該參數能夠用在多個gh-ost同時操做的時候,建立一個文件,讓全部的gh-ost操做中止,或者刪除這個文件,讓全部的gh-ost操做恢復。 -throttle-control-replicas string: 列出全部須要被檢查主從複製延遲的從庫。 -throttle-flag-file string: 當該文件被建立後,gh-ost操做當即中止。該參數適合控制單個gh-ost操做。-throttle-additional-flag-file string適合控制多個gh-ost操做。 -throttle-query string: 節流查詢。每秒鐘執行一次。當返回值=0時不須要節流,當返回值>0時,須要執行節流操做。該查詢會在數據遷移(migrated)服務器上操做,因此請確保該查詢是輕量級的。 -timestamp-old-table: 在舊錶名中使用時間戳。這會使舊錶名稱具備惟一且無衝突的交叉遷移。 -user string :MYSQL用戶
測試例子對 test.b 重建表 alter table b engine=innodb;app
/opt/gh-ost/bin/gh-ost \ --max-load=Threads_running=20 \ --critical-load=Threads_running=50 \ --critical-load-interval-millis=5000 \ --chunk-size=1000 \ --user="root" \ --password="" \ --host='127.0.0.1' \ --port=3316 \ --database="test" \ --table="b" \ --verbose \ --alter="engine=innodb" \ --assume-rbr \ --cut-over=default \ --cut-over-lock-timeout-seconds=1 \ --dml-batch-size=10 \ --allow-on-master \ --concurrent-rowcount \ --default-retries=10 \ --heartbeat-interval-millis=2000 \ --panic-flag-file=/tmp/ghost.panic.flag \ --postpone-cut-over-flag-file=/tmp/ghost.postpone.flag \ --timestamp-old-table \ --execute 2>&1 | tee /tmp/rebuild_t1.log
操做過程當中會生成兩個中間狀態的表 _b_ghc, _b_gho,其中 _b_ghc 是記錄 gh-ost 執行過程的表,其記錄相似以下:
_b_gho 是目標表,也即應用 ddl 語句的幽靈表。
特別說明,上面的命令實際上是在咱們的生產線上直接使用的。通常咱們針對幾百 G 的大表作歸檔刪除數據以後要重建表,以便減小表空間大小。重建完,進行 cut-over 切換幽靈表和原表時,默認不刪除幽靈表。由於直接刪除上百 G 會對磁盤 IO 有必定的影響.
其餘的請各位同行根據本身的狀況去調整合適的參數,注意如下兩個參數。
--ok-to-drop-table:gh-ost操做結束後,刪除舊錶,默認狀態是不刪除舊錶,會存在_tablename_del表。 --timestamp-old-table 最終rename的時候表名會加上時間戳後綴,每次執行的時候都會生成一個新的表名。
gh-ost 擁有衆多特性,好比:輕量級、可暫停、可動態控制、可審計、可測試等等,咱們能夠經過操做特定的文件對正在執行的 gh-ost 命令進行動態調整。
暫停/恢復
咱們能夠經過建立/刪除 throttle-additional-flag-file 指定的文件 /tmp/gh-ost.throttle 控制 gh-ost 對 binlog 應用。
限流
gh-ost 能夠經過 unix socket 文件或者 TCP 端口(可配置)的方式來監聽請求,DBA 能夠在命令運行後更改相應的參數,參考下面的例子:
打開限流
echo throttle | socat - /tmp/gh-ost.test.b.sock
_b_ghc 中會多一條記錄
331 | 2019-08-31 23:23:00 | throttle at 1567264980930907070 | done throttling
關閉限流
no-throttle | socat - /tmp/gh-ost.test.b.sock
_b_ghc 中會多一條記錄
347 | 2019-08-31 23:24:09 | throttle at 1567265049830789079 | commanded by user
改變執行參數:chunk-size= 1024, max-lag-millis=100, max-load=Thread_running=23 這些參數均可以在運行時動態調整。
echo chunk-size=1024 | socat - /tmp/gh-ost.test.b.sock echo max-lag-millis=100 | socat - /tmp/gh-ost.test.b.sock echo max-load=Thread_running=23 | socat - /tmp/gh-ost.test.b.sock
終止運行
咱們經過來過建立 panic-flag-file 指定的文件,當即終止正在執行的 gh-ostmin
建立文件 /tmp/ghost.panic.flag
gh-ost log提示
2019-08-31 22:50:52.701 FATAL Found panic-file /tmp/ghost.panic.flag. Aborting without cleanup
注意中止 gh-ost 操做會有遺留表 xxx_ghc,xxx_gho還有 socket 文件,管理 cut-over 的文件,若是你須要執行兩次請務必檢查指定目錄是否存在這些文件,而且清理掉文件和表。
從功能,穩定性和性能上來看,兩種工具各有千秋,雖然在高併發寫的狀況下,gh-ost 應用 binlog 會出現性能較低不如 pt-osc 的狀況。不過 gh-ost 更靈活,支持咱們根據實際狀況動態調整。
推薦兩個 blog 的文章吧,你們能夠根據本身的實際場景去選擇使用哪一個工具。
https://www.cnblogs.com/zping...
https://blog.csdn.net/poxiaon...
整體來說 gh-ost 是一款很是出色的開源產品,感謝 github 爲咱們 MySQL DBA 提供了一種解決大表 ddl 的工具,歡迎還沒使用的朋友試用該工具。
參考文章
https://www.cnblogs.com/zhouj...
https://segmentfault.com/a/11...