做爲一個DBA,大表的DDL的變動大部分都是使用Percona的pt-online-schema-change,本文說明下另外一種工具gh-ost的使用:不依賴於觸發器,是由於他是經過模擬從庫,在row binlog中獲取增量變動,再異步應用到ghost表的。在使用gh-ost以前,能夠先看GitHub 開源的 MySQL 在線更改 Schema 工具【轉】文章或則官網瞭解其特性和原理。本文只對使用進行說明。html
1)下載安裝:https://github.com/github/gh-ost/tagsmysql
2)參數說明:gh-ost --helpgit
View Codegithub
3)使用說明:條件是操做的MySQL上須要的binlog模式是ROW。若是在一個從上測試也必須是ROW模式,還要開啓log_slave_updates。根據上面的參數說明按照需求進行調整。sql
環境:主庫:192.168.163.131;從庫:192.168.163.130segmentfault
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便可,主庫不須要保證):app
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 和心跳包,用來控制整個流程的進度,檢測狀態等。這種架構帶來諸多好處,例如:
https://github.com/github/gh-ost
GitHub 開源的 MySQL 在線更改 Schema 工具