一般意義上的觸發(fā)器,尤其是基于觸發(fā)器的表定義修改操作,都有如下問題:
觸發(fā)器就是存儲(chǔ)過程,都是解釋型代碼,MySQL不會(huì)做預(yù)編譯。把它們硬嵌入到業(yè)務(wù)操作的事務(wù)空間中,會(huì)給你要修改的表上執(zhí)行的每條操作都增加命令分析和解釋的開銷。
鎖:觸發(fā)器與操作語句分享相同的事務(wù)空間,當(dāng)操作語句釋放了原始表上的鎖之后,觸發(fā)器再去釋放另一張表上的鎖。在同步模式下這樣行為的后果尤其嚴(yán)重。主庫上的鎖競爭與寫并發(fā)有直接關(guān)系。Github在生產(chǎn)環(huán)境中曾經(jīng)遇到過鎖競爭導(dǎo)致的幾乎乃至完全鎖住的情況,完全無法訪問表或者整個(gè)數(shù)據(jù)庫。觸發(fā)器導(dǎo)致的另一種鎖是在創(chuàng)建或銷毀觸發(fā)器時(shí)對元數(shù)據(jù)的鎖。在完成修改表定義之后從比較忙的表上刪除觸發(fā)器時(shí),甚至曾經(jīng)碰到幾十秒甚至幾分鐘無法提供服務(wù)的情況。
無法暫停:當(dāng)主庫業(yè)務(wù)負(fù)載開始增高時(shí),你可能會(huì)想要暫停或者取消還沒完成的修改表定義的任務(wù)??墒腔谟|發(fā)器的方案沒辦法這么做。也許你可以暫停行拷貝的操作,但卻不能暫停觸發(fā)器,因?yàn)榘延|發(fā)器停掉會(huì)導(dǎo)致臨時(shí)表中丟數(shù)據(jù)。所以,在整個(gè)過程中觸發(fā)器都必須一直處于工作狀態(tài)。在一些繁忙的服務(wù)器上,曾經(jīng)出現(xiàn)過即使把在線操作全停掉,最后主庫還是被觸發(fā)器給拖死的情況。
并發(fā)修改:大家都希望能同時(shí)修改多張表的定義??紤]到上面分析的觸發(fā)器的代價(jià),在生產(chǎn)系統(tǒng)中Github并不敢以觸發(fā)器的模式同時(shí)修改多張表的定義,事實(shí)上也沒聽說有哪家公司真的在線上這么干。
測試:大家也許想測試一下修改方案是否可行,評估一下負(fù)載。基于觸發(fā)器的方案只能在從庫上通過基于語句的復(fù)制來模擬一下,由于從庫上的復(fù)制操作是單線程的(即使用了多線程復(fù)制的方案,大部分情況下也還是這樣的),這樣遠(yuǎn)不能模擬出在主庫上修改過程中的真實(shí)情況。
gh-ost
gh-ost是gitHub’s Online Schema Transmogrifier/Transfigurator/Transformer/Thingy的縮寫,意思是GitHub的在線表定義轉(zhuǎn)換器。

gh-ost有以下特點(diǎn):
無觸發(fā)器
輕量級(jí)
可暫停
動(dòng)態(tài)可控
可審計(jì)
可測試
可靠性高
無觸發(fā)器
gh-ost不使用觸發(fā)器,它跟蹤二進(jìn)制日志文件,在對原始表的修改提交之后,用異步方式把這修改內(nèi)容應(yīng)用到臨時(shí)表中去。
gh-ost希望二進(jìn)制文件使用基于行的日志格式,但這并不表示如果主庫上使用的是基于語句的日志格式,就不能用它來在線修改表定義了。事實(shí)上,Github常用的方式是用一個(gè)從庫把日志的語句模式轉(zhuǎn)成行模式,再從這個(gè)從庫上去讀日志。搭一個(gè)這樣的從庫并不復(fù)雜。
輕量級(jí)
因?yàn)椴恍枰褂糜|發(fā)器,gh-ost把修改表定義的負(fù)載和正常的業(yè)務(wù)負(fù)載解耦開了。它不需要考慮被修改的表上的并發(fā)操作和競爭等,這些在二進(jìn)制日志中都被序列化了,gh-ost只操作臨時(shí)表,完全與原始表不相干。事實(shí)上,gh-ost也把行拷貝的寫操作與二進(jìn)制日志的寫操作序列化了,這樣,對主庫來說只是有一條連接在順序的向臨時(shí)表中不斷寫入數(shù)據(jù),這樣的行為與常見的ETL相當(dāng)不同。
可暫停
因?yàn)樗袑懖僮鞫际莋h-ost生成的,而讀取二進(jìn)制文件本身就是一個(gè)異步操作,所以在暫停時(shí),gh-ost是完全可以把所有對主庫的寫操作全都暫停的。暫停就意味著對主庫沒有寫入和更新。不過gh-ost也有一張內(nèi)部狀態(tài)跟蹤表,即使在暫停狀態(tài)下也會(huì)向那張表中不斷寫入心跳信息,寫入量可以忽略不計(jì)。
gh-ost提供了比簡單的暫停更多的功能,除了暫停之外還可以做:
負(fù)載:與pt-online-schema-change相近的一個(gè)功能,用戶可以設(shè)置MySQL指標(biāo)的閾值,比如設(shè)置Threads_running=30。
復(fù)制延遲:gh-ost內(nèi)置了心跳功能來檢查復(fù)制延遲。用戶可以指定查看哪個(gè)從庫的延遲,gh-ost默認(rèn)是直接查看它連上的那個(gè)從庫。
命令:用戶可以寫一些命令,根據(jù)輸出結(jié)果來決定要不要開始操作。比如:SELECT HOUR(NOW()) BETWEEN 8 and 17.
上述所有指標(biāo)即使在修改表定義的過程中也可以動(dòng)態(tài)修改。
標(biāo)志位文件:生成一個(gè)標(biāo)志位文件,gh-ost就會(huì)立刻暫停。刪除文件,gh-ost又會(huì)恢復(fù)工作。