1. 程式人生 > >MySQL線上DDL gh-ost 使用說明

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

DDL過程

複製程式碼

① 檢查有沒有外來鍵和觸發器。
② 檢查表的主鍵資訊。
③ 檢查是否主庫或從庫,是否開啟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 工具

Online DDL 工具 gh-ost 支援阿里雲 RDS

gh-ost:不一樣的線上表結構變更

GitHub開源MySQL Online DDL工具gh-ost