MySQL線上DDL gh-ost 使用說明
背景:
作為一個DBA,大表的DDL的變更大部分都是使用Percona的pt-online-schema-change,本文說明下另一種工具gh-ost的使用:不依賴於觸發器,是因為他是通過模擬從庫,在row binlog中獲取增量變更,再非同步應用到ghost表的。在使用gh-ost之前,可以先看GitHub 開源的 MySQL 線上更改 Schema 工具【轉】文章或則官網瞭解其特性和原理。本文只對使用進行說明。
說明:
1)下載安裝:https://github.com/github/gh-ost/tags
2)引數說明:gh-ost --help
View Code
3)使用說明:條件是操作的MySQL上需要的binlog模式是ROW。如果在一個從上測試也必須是ROW模式,還要開啟log_slave_updates。根據上面的引數說明按照需求進行調整。
環境:主庫:192.168.163.131;從庫:192.168.163.130
① 檢查有沒有外來鍵和觸發器。 ② 檢查表的主鍵資訊。 ③ 檢查是否主庫或從庫,是否開啟log_slave_updates,以及binlog資訊 ④ 檢查gho和del結尾的臨時表是否存在 ⑤ 建立ghc結尾的表,存資料遷移的資訊,以及binlog資訊等 ---以上校驗階段 ⑥ 初始化stream的連線,新增binlog的監聽 ---以下遷移階段 ⑥ 建立gho結尾的臨時表,執行DDL在gho結尾的臨時表上 ⑦ 開啟事務,按照主鍵id把源表資料寫入到gho結尾的表上,再提交,以及binlog apply。 ---以下cut-over階段 ⑧ lock源表,rename 表:rename 源表 to 源_del表,gho表 to 源表。 ⑨ 清理ghc表。
1. 單例項上DDL: 單個例項相當於主庫,需要開啟--allow-on-master引數和ROW模式。
gh-ost --user="root" --password="root" --host=192.168.163.131 --database="test" --table="t1" --alter="ADD COLUMN cc2 varchar(10),add column cc3 int not null default 0 comment 'test' " --allow-on-master --execute
2. 主從上DDL:
有2個選擇,一是按照1直接在主上執行同步到從上,另一個連線到從庫,在主庫做遷移(只要保證從庫的binlog為ROW即可,主庫不需要保證):
gh-ost --user="root" --password="root" --host=192.168.163.130 --database="test" --table="t" --initially-drop-old-table --alter="ADD COLUMN y1 varchar(10),add column y2 int not null default 0 comment 'test' " --execute
此時的操作大致是:
-
行資料在主庫上讀寫
-
讀取從庫的二進位制日誌,將變更應用到主庫
-
在從庫收集表格式,欄位&索引,行數等資訊
-
在從庫上讀取內部的變更事件(如心跳事件)
-
在主庫切換表
在執行DDL中,從庫會執行一次stop/start slave,要是確定從的binlog是ROW的話可以新增引數:--assume-rbr。如果從庫的binlog不是ROW,可以用引數--switch-to-rbr來轉換成ROW,此時需要注意的是執行完畢之後,binlog模式不會被轉換成原來的值。--assume-rbr和--switch-to-rbr引數不能一起使用。
3. 在從上進行DDL測試:
gh-ost --user="root" --password="root" --host=192.168.163.130 --database="test" --table="t" --alter="ADD COLUMN abc1 varchar(10),add column abc2 int not null default 0 comment 'test' " --test-on-replica --switch-to-rbr --execute
引數--test-on-replica:在從庫上測試gh-ost,包括在從庫上資料遷移(migration),資料遷移完成後stop slave,原表和ghost表立刻交換而後立刻交換回來。繼續保持stop slave,使你可以對比兩張表。如果不想stop slave,則可以再新增引數:--test-on-replica-skip-replica-stop
上面三種是gh-ost操作模式,上面的操作中,到最後不會清理臨時表,需要手動清理,再下次執行之前果然臨時表還存在,則會執行失敗,可以通過引數進行刪除:
--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失敗。 --ok-to-drop-table:gh-ost操作結束後,刪除舊錶,預設狀態是不刪除舊錶,會存在_tablename_del表。
還有其他的一些引數,比如:--exact-rowcount、--max-lag-millis、--max-load等等,可以看上面的說明,具體大部分常用的引數命令如下:
gh-osc --user= --password= --host= --database= --table= --max-load=Threads_running=30, --chunk-size=1000 --serve-socket-file=/tmp/gh-ost.test.sock --exact-rowcount --allow-on-master/--test-on-replica --initially-drop-ghost-table/--initially-drop-old-table/--initially-drop-socket-file --max-lag-millis= --max-load='Threads_running=100,Threads_connected=500' --ok-to-drop-table
4)額外說明:終止、暫停、限速
gh-ost --user="root" --password="root" --host=192.168.163.131 --database="test" --table="t1" --alter="ADD COLUMN o2 varchar(10),add column o1 int not null default 0 comment 'test' " --exact-rowcount --serve-socket-file=/tmp/gh-ost.t1.sock --panic-flag-file=/tmp/gh-ost.panic.t1.flag --postpone-cut-over-flag-file=/tmp/ghost.postpone.t1.flag --allow-on-master --execute
① 標示檔案終止執行:--panic-flag-file
建立檔案終止執行,例子中建立/tmp/gh-ost.panic.t1.flag檔案,終止正在執行的gh-ost,臨時檔案清理需要手動進行。
② 表示檔案禁止cut-over進行,即禁止表名切換,資料複製正常進行。--postpone-cut-over-flag-file
建立檔案延遲cut-over進行,即推遲切換操作。例子中建立/tmp/ghost.postpone.t1.flag檔案,gh-ost 會完成行復制,但並不會切換表,它會持續的將原表的資料更新操作同步到臨時表中。
③ 使用socket監聽請求,操作者可以在命令執行後更改相應的引數。--serve-socket-file,--serve-tcp-port(預設關閉)
建立socket檔案進行監聽,通過介面進行引數調整,當執行操作的過程中發現負載、延遲上升了,不得不終止操作,重新配置引數,如 chunk-size,然後重新執行操作命令,可以通過scoket介面進行動態調整。如:
暫停操作:
#暫停 echo throttle | socat - /tmp/gh-ost.test.t1.sock #恢復 echo no-throttle | socat - /tmp/gh-ost.test.t1.sock
修改限速引數:
echo chunk-size=100 | socat - /tmp/gh-ost.t1.sock echo max-lag-millis=200 | socat - /tmp/gh-ost.t1.sock echo max-load=Thread_running=3 | socat - /tmp/gh-ost.t1.sock
4)和pt-online-schema-change對比測試
1. 表沒有寫入並且引數為預設的情況下,二者DDL操作時間差不多,畢竟都是copy row操作。
2. 表有大量寫入(sysbench)的情況下,因為pt-osc是多執行緒處理的,很快就能執行完成,而gh-ost是模擬“從”單執行緒應用的,極端的情況下,DDL操作非常困難的執行完畢。
結論:雖然pt-osc不需要觸發器,對於主庫的壓力和效能影響也小很多,但是針對高併發的場景進行DDL效率還是比pt-osc低,所以還是需要在業務低峰的時候處理。相關的測試可以看gh-ost和pt-osc效能對比。
5)封裝指令碼:
環境:M:192.168.163.131(ROW),S:192.168.163.130/132
封裝指令碼:gh-ost.py
View Code
執行:
View Code
總結:
gh-ost 放棄了觸發器,使用 binlog 來同步。gh-ost 作為一個偽裝的備庫,可以從主庫/備庫上拉取 binlog,過濾之後重新應用到主庫上去,相當於主庫上的增量操作通過 binlog 又應用回主庫本身,不過是應用在幽靈表上。
gh-ost 首先連線到主庫上,根據 alter 語句建立幽靈表,然後作為一個”備庫“連線到其中一個真正的備庫上,一邊在主庫上拷貝已有的資料到幽靈表,一邊從備庫上拉取增量資料的 binlog,然後不斷的把 binlog 應用回主庫。圖中 cut-over 是最後一步,鎖住主庫的源表,等待 binlog 應用完畢,然後替換 gh-ost 表為源表。gh-ost 在執行中,會在原本的 binlog event 裡面增加以下 hint 和心跳包,用來控制整個流程的進度,檢測狀態等。這種架構帶來諸多好處,例如:
- 整個流程非同步執行,對於源表的增量資料操作沒有額外的開銷,高峰期變更業務對效能影響小。
- 降低寫壓力,觸發器操作都在一個事務內,gh-ost 應用 binlog 是另外一個連線在做。
- 可停止,binlog 有位點記錄,如果變更過程發現主庫效能受影響,可以立刻停止拉binlog,停止應用 binlog,穩定之後繼續應用。
- 可測試,gh-ost 提供了測試功能,可以連線到一個備庫上直接做 Online DDL,在備庫上觀察變更結果是否正確,再對主庫操作,心裡更有底。
參考文件:
https://github.com/github/gh-ost
GitHub 開源的 MySQL 線上更改 Schema 工具