gh-ost的學習

czxin788發表於2019-12-23

    公司內部一直使用的online ddl工具是pt-online-schema-change,今天準備嘗試一下另外一個工具gh-ost。

    我根據百度出的文件進行學習,下面總結成自己的知識。

    gh-ost 是 gitHub,s Online Schema Transmogrifier/Transfigurator/Transformer/Thingy 的縮寫,意思是 GitHub 的線上表定義轉換器。

    我對gh-ost的感興趣的原因是gh-ost可隨時暫停。如果變更過程發現主庫效能受影響,可以立刻停止拉binlog,停止應用 binlog,停止移動行資料,等效能穩定之後再繼續;另外,gh-ost不依賴觸發器,這是和pt-osc的最大區別。

大致的工作原理:

只以主庫模式介紹:

1、 gh-ost 首先連線到主庫上,根據 alter 語句建立幽靈表_tablename_gho;
  
2、 然後gh-ost作為一個備庫連線到主庫上,一邊在主庫上複製已有的資料到幽靈表,
一邊從主庫上拉取增量資料的 binlog,然後不斷的把 binlog 應用回主庫幽靈表;
  
3、 等待全部資料同步完成,進行cut-over,即進行幽靈表和原表切換。cut-over是最後一步,
鎖住主庫的源表,等待binlog應用完畢,然後替換gh-ost幽靈表為源表。gh-ost在執行中,
會在原本的binlog event裡面增加hint和心跳包,用來控制整個流程的進度,檢測狀態等。

下載安裝

    從 github 釋出地址下載最新的 binary 包:

    解壓後就一個 gh-ost 二進位制檔案。

 tar -xvf  gh-ost-binary-linux-20190214020851.tar.gz
 cp gh-ost /usr/bin

常用命令組合

只以主庫模式介紹,上生產可以直接用:

gh-ost \
 --max-load=Threads_running=50 \
 --critical-load=Threads_running=80 \
 --critical-load-interval-millis=5000 \
 --max-lag-millis=1500 \
 --chunk-size=1000 \
 --ok-to-drop-table \
 --initially-drop-ghost-table \
 --initially-drop-socket-file \
 --host=172.18.6.2 \
 --port=3306 \
 --user="chenzhixin" \
 --password="123456"\
 --database="test" \
 --table="user100w"  \
 --verbose \
 --alter="add column test_field6 varchar(256) default '';" \
 --cut-over-lock-timeout-seconds=1 \
 --dml-batch-size=10 \
 --exact-rowcount  \
 --serve-socket-file=/tmp/ghost.sock \
 --panic-flag-file=/tmp/ghost.panic.flag  \
 --allow-on-master \
 --execute
 
 ##########  特別提醒!!!!!!############################
 下面這個引數有需要再加,加了它就不會自動切換源表和幽靈表,需要手工刪除/tmp/ghost.postpone.flag
 檔案後,才會發生自動切換,請理解該引數含義。
 --postpone-cut-over-flag-file=/tmp/ghost.postpone.flag

    操作過程中會生成兩個中間狀態的表 _tablename_ghc和_tablename_gho,其中 _tablename_ghc 是記錄gh-ost 執行過程的表,_tablename_gho 是目標表,也即應用ddl語句的幽靈表_tablename_gho。

    執行上述的gh-ost命令過程中,會看到如下的_user100w_ghc的執行過程表,和 _user100w_gho幽靈表、

mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| _user100w_ghc  |
| _user100w_gho  |
| fruits         |
| test_timestamp |
| user100w       |
+----------------+
5 rows in set (0.00 sec)

    解釋:

--max-load=Threads_running=50 
  表面如果在執行gh-ost的過程中出現Threads_running=50則暫停gh-ost的執行
--critical-load=Threads_running=80 
 表明執行過程中出現Threads_running達到80則終止gh-ost的執行
--critical-load-interval-millis 當值為0時,當達到-critical-load,gh-ost立即退出。當值不為0時,當達到-critical-load,gh-ost會在-critical-load-interval-millis秒數後,再次進行檢查,再次檢查依舊達到-critical-load,gh-ost將會退出
--max-lag-millis
  會監控從庫的主從延遲情況,如果延遲秒數超過這個閥值,row copy不會退出,等待延遲秒數低於這個閥值繼續遷移。
--ok-to-drop-table
 go-ost 執行完以後是否刪除老表,加上此引數會自動刪除老表。預設不刪除老表,會存在_tablename_del表
--initially-drop-ghost-table
 gh-ost 執行前會建立兩張 xx_ghc 和 xx_gho 表,如果這兩張表存在,且加上了這個引數,那麼會自動刪除原 gh 表,從新建立,否則退出。xx_gho 表相當於老表的全量備份,xx_ghc 表資料是資料更改日誌,理解成增量備份。
--initially-drop-socket-file
 gh-ost 執行時會建立 socket 檔案,退出時不會刪除,下次執行 gh-ost 時會報錯,加上這個引數會刪除老的 socket 檔案,重新建立。
--throttle-flag-file
 此檔案存在時操作暫停,刪除檔案操作會繼續。
--verbose
 執行過程輸出日誌
--chunk-size
 遷移過程是一步步分批次完成的,這個引數是指事務每次提交的行數,預設是 1000。
--max-lag-millis
 會監控從庫的主從延遲情況,如果延遲秒數超過這個閥值,遷移不會退出,等待延遲秒數低於這個閥值繼續遷移。
--max-lag-millis
 會監控從庫的主從延遲情況,如果延遲秒數超過這個閥值,遷移不會退出,等待延遲秒數低於這個閥值繼續遷移
--throttle-control-replica
  和--max-lag-millis 引數相結合,這個引數指定主從延遲的資料庫例項。
--cut-over-lock-timeout-seconds      
  gh-ost在cut-over階段最大的鎖等待時間,當鎖超時時,gh-ost的cut-over將重試。(預設值:3)
--allow-on-master
 整個遷移所有操作在主庫上執行
--dml-batch-size   
  在單個事務中應用DML事件的批次大小(範圍1-100)(預設值為10)
--exact-rowcount 
  準確統計表行數(使用select count(*)的方式),得到更準確的預估時間。
--postpone-cut-over-flag-file 
  當這個檔案存在的時候,gh-ost的cut-over階段將會被推遲,資料仍然在複製,直到該檔案被刪除。
--throttle-flag-file string
  當該檔案被建立後,gh-ost操作立即停止。該引數適合控制單個gh-ost操作。-throttle-additional-flag-file string適合控制多個gh-ost操作。

進度提示

    執行gh-ost中,會有輸出資訊,具體解釋如下:

Copy: 27000/58707 46.0%;58707指需要遷移總行數,27000指已經遷移的行數,46%指遷移完成的百分比。
Applied: 0,指在二進位制日誌中處理的event數量。在上面的例子中,遷移表沒有流量,因此沒有被處理日誌event。
Backlog: 0/1000,表示我們在讀取二進位制日誌方面表現良好,在二進位制日誌佇列中沒有任何積壓(Backlog)事件。
Backlog: 7/1000,當複製行時,在二進位制日誌中積壓了一些事件,並且需要應用。
Backlog: 1000/1000,表示我們的1000個事件的緩衝區已滿(程式寫死的1000個事件緩衝區,低版本是100個),此時就注意binlog寫入量非常大,gh-ost處理不過來event了,可能需要暫停binlog讀取,需要優先應用緩衝區的事件。
streamer: shvm-5-39.000040:338912890;表示當前已經應用到binlog檔案位置

控制gh-ost的過程

#首先要安裝socat工具

yum install socat -y

    注意:上面gh-ost裡面配置的--serve-socket-file=/tmp/ghost.sock,下面就用到了。

    gh-ost 可以透過 unix socket 檔案的方式來監聽請求,DBA 可以在gh-ost命令執行後更改相應的引數進行限流操作等。

#暫停

echo throttle | socat - /tmp/ghost.sock

#恢復

echo no-throttle | socat - /tmp/ghost.sock

#終止

對應panic-flag-file引數檔案,當tmp目錄存在該檔案立即停止
touch /tmp/ghost.panic.flag

#延遲切換(cut-over階段)

--postpone-cut-over-flag-file=/tmp/ghost.postpone.flag
當設定該引數時cut-over一直延遲源表和幽靈表的切換,直到你刪除該檔案才進行切換。

適用場景:

你發起了一次修改操作,然後估計完成時間是凌晨 2 點鐘,可是你又非常關心最後的切換操作,
非常想看著它切換,這可怎麼辦?只需要一個標誌位檔案就可以告訴 gh-ost 推遲切換了,
這樣 gh-ost 會只做完複製資料的操作,但不會切換表。它還會仍然繼續同步資料,
保持幽靈表的資料處於同步狀態。等第二天早上你回到辦公室之後,
刪除標誌位檔案或者向gh-ost傳送命令echo unpostpone,它就會做切換了。
我們不希望軟體強迫我們看著它做事情,它應該把我們解放出來,讓人去做人該做的事。

#線上修改限速引數

echo max-load=Threads_connected=200  | socat - /tmp/ghost.sock
echo max-load=Thread_running=3 | socat - /tmp/ghost.sock
echo chunk-size=100 | socat - /tmp/ghost.sock
echo max-lag-millis=200 | socat - /tmp/ghost.sock

適用場景:

當你執行了 gh-ost 之後,也許你會看見主庫的負載變高了,那你可以發出暫停命令。
用 echo throttle 命令生成一個檔案,看看主庫的負載會不會又變得正常。試一下這些命令,
你就可以知道你可以怎樣控制它的行為,你的心裡就會安定許多。

gh-ost的限制

    凡事有利必有弊,人不可能把所有好事都佔有,下面是gh-ost的幾個限制:

    1、不支援沒有主鍵或者唯一索引的表

    2、不支援有外來鍵約束的表(主表和子表都不支援)

    3、不支援表上有觸發器

    5、表上存在大量寫入的時候,gh-ost可能永遠也完成不了

    經過測試:當寫入QPS 5000以上,gh-ost無法完成任務,其原因是apply binlog是單執行緒,可以理解為slave,當原表寫入量巨大時(QPS=5000以上),一直在應用日誌,而gh-ost設計是binlog應用優先順序高於row copy,所以我們看到row copy進度一直沒變,這樣如果原表一直壓力這麼大,那麼gh-ost DDL將無法完成。經過在s3710機器上測試如果原表寫入的QPS大於5000將大機率出現此情況,小於5000的話沒問題。

參考連結

https://cloud.tencent.com/developer/article/1072238

https://blog.csdn.net/weixin_34037173/article/details/94467359

https://www.cnblogs.com/mysql-dba/p/9901607.html



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28916011/viewspace-2670103/,如需轉載,請註明出處,否則將追究法律責任。

相關文章