[翻译]Triggerless design.md
源文將持續(xù)更新,請(qǐng)點(diǎn)擊此處閱讀原文
介紹gh-ost不使用Trigger背后的邏輯和算法,其次是這樣設(shè)計(jì)的含義,優(yōu)點(diǎn),以及缺點(diǎn)。
基于觸發(fā)器遷移的理念
這里有兩個(gè)比較流行的online DDL工具:
pt-online-schema-change
Facebook OSC
前者使用同步設(shè)計(jì)原理:它在原表上創(chuàng)建三個(gè)觸發(fā)器(AFTER INSERT,AFTER UPDATE,AFTER DELETE)。每個(gè)觸發(fā)器將原表上的操作重播到ghost表中。因此,原表上的每一個(gè)UPDATE都會(huì)被重播到gh-ost表中,INSERT/DELETE也是如此。觸發(fā)器和原表的操作存在與同一個(gè)事務(wù)空間里。
后者使用異步設(shè)計(jì)原理:它在原表上創(chuàng)建三個(gè)觸發(fā)器(AFTER INSERT,AFTER UPDATE,AFTER DELETE)。它也會(huì)創(chuàng)建一個(gè)changelog表。觸發(fā)器不會(huì)直接將原表操作重播到ghost表中。取而代之的是,它會(huì)在changelog中添加一條記錄。原表上的UPDATE操作在changelog表中插入一條記錄像"原表上有一個(gè)UPDATE操作,將這個(gè)值變?yōu)榱肆硗庖粋€(gè)值",INSERT/DELETE也是如此。一個(gè)后臺(tái)的線程會(huì)實(shí)時(shí)去查看changelog表的變化,并應(yīng)用所有的變更應(yīng)用到ghost表上。這是一個(gè)異步的操作,因?yàn)間h-ost重播操作的過(guò)程與原表的操作不在相同的事務(wù)空間中了,并且gh-ost的重播操作可能會(huì)延遲。值得注意的是,changelog的記錄寫(xiě)入操作還是與原表操作存在于相同的事務(wù)空間中。
不基于觸發(fā)器的異步遷移理念
gh-os使用不基于觸發(fā)器的異步遷移方案。但是它不需要觸發(fā)器,因?yàn)樗幌馞B工具那樣需要一個(gè)changelog表。因?yàn)樗皇腔赾hangelog表做數(shù)據(jù)遷移,而是基于MySQL二進(jìn)制日志(binlog)。
gh-ost基于binlog_format=row(RBR)獲取來(lái)源于原表的記錄,你也可以基于binlog_format=statement(SBR)獲取記錄,詳情請(qǐng)點(diǎn)擊。
RBR格式的二進(jìn)制日志將復(fù)雜的SQL語(yǔ)句(可能存在多表)分解為不同的單表單行記錄,這樣更易于將binlog應(yīng)用到gh-ost上。
gh-ost將自己偽裝成MySQL從庫(kù):gh-ost連上主庫(kù),并且從主庫(kù)獲取binlog。因此,它獲取binlog日志,并且通過(guò)過(guò)濾得到原表的操作事件。
gh-ost可以直接連接到主庫(kù)上,但是gh-ost更喜歡連接到一個(gè)從庫(kù)上。但是該從庫(kù)需要設(shè)置參數(shù)log_slave_updates=1和binlog_format=row(binlog_format也可以通過(guò)調(diào)整gh-ost參數(shù)來(lái)進(jìn)行自動(dòng)設(shè)置)。
讀取二進(jìn)制日志,特別是在在從庫(kù)上讀取二進(jìn)制,進(jìn)一步強(qiáng)調(diào)了算法的異步性。當(dāng)有一個(gè)事物寫(xiě)入到了binlog中,它依舊需要等gh-ost偽裝成一個(gè)從庫(kù)之后,才開(kāi)始獲取binlog并且應(yīng)用到gh-ost中。
異步設(shè)計(jì)也意味著有很多值得注意的因素,稍后將做討論。
工作流程概覽
整個(gè)工作流程包括:原表上讀取表數(shù)據(jù),binlog讀取操作事件,檢查主從延遲以及其它的節(jié)流參數(shù),將變更應(yīng)用到ghost表中(通常是master上的ghost表),通過(guò)二進(jìn)制日志流發(fā)送提示等等。
工作流程如下:
初始化設(shè)置&驗(yàn)證
初始化設(shè)置不是一個(gè)并發(fā)操作。
連接從庫(kù)(推薦)/主庫(kù),檢查主庫(kù)標(biāo)志
預(yù)驗(yàn)證ALTER語(yǔ)句
初始化驗(yàn)證:權(quán)限以及表是否存在
創(chuàng)建changelog和ghost表
在ghost表上執(zhí)行ALTER語(yǔ)句
對(duì)比原表和ghost表的結(jié)構(gòu),檢查共享列,共享唯一鍵,驗(yàn)證是否有外鍵,選擇共享的唯一鍵,這個(gè)鍵用于處理表的唯一標(biāo)識(shí),比如數(shù)據(jù)遷移等
開(kāi)始監(jiān)聽(tīng)binlog,監(jiān)聽(tīng)changelog表的事件
在changelog表上注入"good to go"的記錄(被二進(jìn)制日志攔截)
開(kāi)始監(jiān)聽(tīng)原表DML的binlog事件
獲取之前原表和ghost表的共享唯一鍵在原表上的最小值和最大值
數(shù)據(jù)復(fù)制流程
該步驟包括多個(gè)移動(dòng)部分,所有操作相互協(xié)調(diào)并發(fā)執(zhí)行。
設(shè)置一個(gè)心跳機(jī)制:頻繁的寫(xiě)入到changelog表(這是一個(gè)低負(fù)載的操作)
心跳機(jī)制不斷的更新?tīng)顟B(tài)
定期(頻繁)檢查潛在的節(jié)流信息或者提示
在原表上通過(guò)行范圍控制,將原表數(shù)據(jù)拆分為一個(gè)chunk一個(gè)chunk,并且添加到數(shù)據(jù)遷移任務(wù)隊(duì)列中
通過(guò)binlog獲取原表的DML語(yǔ)句,并且添加到binlog重播任務(wù)隊(duì)列中
處理數(shù)據(jù)遷移任務(wù)隊(duì)列和binlog重播任務(wù)隊(duì)列,并將其順序的應(yīng)用到ghost表上(當(dāng)遇到節(jié)流操作或者h(yuǎn)int提示時(shí),將會(huì)暫停該操作)
當(dāng)數(shù)據(jù)遷移與binlog重播完成后,將會(huì)在changelog表上注入/攔截"copy all done"的記錄
當(dāng)-postpone-cut-over-flag-file參數(shù)設(shè)置的文件存在時(shí),將會(huì)推遲接下來(lái)的cut-over操作(但是原表的DML操作依舊會(huì)通過(guò)binlog應(yīng)用到ghost表上)
結(jié)束操作:交換表流程
將原表加上寫(xiě)鎖,binlog事件會(huì)繼續(xù)應(yīng)用在gh-ost上(該步驟是個(gè)異步操作,因此即使表被鎖住,gh-ost仍然可以處理隊(duì)列中未處理完的binlog事件)
-
將原表rename為_(kāi)tablename_del表,ghost則rename為tablename表
rename /* gh-ost */ table `wing`.`t` to `wing`.`_t_del`, `wing`.`_t_gho` to `wing`.`t` 清理工作:刪除需要被清除的表
異步設(shè)計(jì)優(yōu)點(diǎn)
Cut-over階段
異步設(shè)計(jì)最復(fù)雜的地方在于cut-over階段:原表和ghost表的交換。在同步設(shè)計(jì)中,由于原表操作與觸發(fā)器操作是在同一個(gè)事物空間中的,所以原表和ghost表的數(shù)據(jù)始終是同步的,因此一個(gè)簡(jiǎn)單的原表和ghost表交換(Rename)是可以存在的。
在異步設(shè)計(jì)中,即使我們對(duì)原表加鎖,管道中仍然會(huì)存在一些事件,binlog日志依舊會(huì)將來(lái)自原表的事件重播到ghost表上。采用同步設(shè)計(jì)中交換表的方式是不可取的,因?yàn)檫@意味著,即使還沒(méi)有對(duì)來(lái)自原表的事件重播完畢,就開(kāi)始使用重命名后的ghost表了,這將造成數(shù)據(jù)不一致。
Facebook的使用"中斷機(jī)制",二步重命名法:
鎖住原表,處理積壓的事件(backlog)
將原表重命名
將ghost重命名為原表的名字
在兩個(gè)表交換的時(shí)候,會(huì)有一個(gè)表不存在的階段,因此會(huì)存在"表中斷"的問(wèn)題。
gh-ost通過(guò)"two-step"算法解決這個(gè)問(wèn)題,"two-step"算法會(huì)阻塞表寫(xiě)入,然后將兩表交換。它使操作很安全,要么成功,要么失敗則回滾到cut-over階段之前。
更多的信息請(qǐng)閱讀cut-over
分離去耦
不使用觸發(fā)器的異步設(shè)計(jì)最大的影響在于工作負(fù)載的去耦。使用觸發(fā)器的設(shè)計(jì),不管是同步還是異步方法,原表上的每一個(gè)寫(xiě)入意味著需要立刻在另外一張表上寫(xiě)入。
We will break down the meaning of workload decoupling, shortly. But it is important to understand that gh-ost interprets the situation in its own time and acts in its own time, yet still makes this an online operation.
The decoupling is important not only as the tool's logic goes, but very importantly as the master server sees it. As far as the master knows, write to the table and writes to the ghost table are unrelated
寫(xiě)負(fù)載
不使用觸發(fā)器意味著主庫(kù)不需要有過(guò)多的寫(xiě)負(fù)載用在存儲(chǔ)過(guò)程上,以及對(duì)gh-ost表的鎖爭(zhēng)用上。
將原表操作重播到ghost表上完全由gh-ost工具完成。因此gh-ost可以決定何時(shí)將數(shù)據(jù)寫(xiě)入到ghost表中。為了分解原表的寫(xiě)負(fù)載,gh-ost工具選擇使用一個(gè)單獨(dú)的線程將原表操作重播到ghost表上。
MySQL對(duì)一個(gè)表大量并發(fā)寫(xiě)入的時(shí)候性能不是很好,這個(gè)時(shí)候鎖變成了一個(gè)很大的問(wèn)題。This is why we choose to alternate between the massive row-copy and the ongoing binlog events backlog such that the server only sees writes from a single connection。
更有趣的是,gh-ost是唯一寫(xiě)入到ghost表的程序,沒(méi)有人意識(shí)到ghost表的存在。因此,gh-ost工具不存在由觸發(fā)器產(chǎn)生的高并發(fā)性問(wèn)題以及資源高爭(zhēng)用問(wèn)題。
可暫停性
當(dāng)gh-ost暫停工作(節(jié)流導(dǎo)致),此時(shí)將會(huì)沒(méi)有任何數(shù)據(jù)寫(xiě)入到ghost表中。因?yàn)間h-ost不存在觸發(fā)器,寫(xiě)負(fù)載是與gh-ost寫(xiě)負(fù)載分開(kāi)的。并且由于gh-ost使用異步設(shè)計(jì)的方法,gh-ost算法已經(jīng)處理了主庫(kù)寫(xiě)入與ghost表寫(xiě)入的時(shí)間差。對(duì)于gh-ost來(lái)說(shuō),幾毫秒的時(shí)間差與幾小時(shí)的時(shí)間差并沒(méi)有任何區(qū)別,對(duì)于gh-ost的運(yùn)行并沒(méi)有任何的影響。
當(dāng)gh-ost進(jìn)行節(jié)流操作的時(shí)候,不管是因?yàn)橹鲝膹?fù)制延遲,還是達(dá)到max-load設(shè)置閥值等,原表還是正常操作。僅僅只是對(duì)ghost表沒(méi)有任何的寫(xiě)操作。除了changelog表上的heartbeat在不斷的更新,但這個(gè)操作帶來(lái)的性能影響是可以忽略不計(jì)的。
可測(cè)試性
我們甚至可以測(cè)試數(shù)據(jù)遷移(migration)步驟:就像我們將數(shù)據(jù)遷移的操作與主庫(kù)的負(fù)載分開(kāi)一樣,我們不在主庫(kù)上應(yīng)用所有的變更,我們選擇一個(gè)從庫(kù),這樣我們可以在從庫(kù)上進(jìn)行表的數(shù)據(jù)遷移(migration)。
這本身是一個(gè)很不錯(cuò)的功能;它為我們提供了測(cè)試的可能性:正如我們完成數(shù)據(jù)遷移一樣,我們從庫(kù)的復(fù)制(stop slave)。gh-ost會(huì)進(jìn)行cut-over階段,但是gh-ost也會(huì)回滾回去。gh-ost測(cè)試時(shí)不會(huì)刪除任何的表。結(jié)果是從庫(kù)上的原表和ghost表都會(huì)存在,也不會(huì)做進(jìn)一步的變更操作(因?yàn)榇藭r(shí)主從復(fù)制已經(jīng)停止)。我們可以對(duì)兩張表進(jìn)行對(duì)比。
這個(gè)方法可以用于驗(yàn)證gh-ost工具的正確性:在多個(gè)生產(chǎn)從庫(kù)上不斷的重復(fù)的做"數(shù)據(jù)遷移"(實(shí)際上并不會(huì)修改列)。每次數(shù)據(jù)遷移后都對(duì)原表和ghost表做一次數(shù)據(jù)校驗(yàn)。gh-ost預(yù)計(jì)是所有的表數(shù)據(jù)校驗(yàn)都是一致的。
多表并發(fā)操作
gh-ost可以運(yùn)行多個(gè)不同的表并發(fā)操作(當(dāng)然不是在相同的表上并發(fā)操作)。gh-ost異步設(shè)計(jì)的方法是支持多個(gè)不同的表并發(fā)操作的。事實(shí)上沒(méi)有觸發(fā)器的存在,多個(gè)不同的表并發(fā)操作gh-ost對(duì)于主庫(kù)來(lái)說(shuō),只是并發(fā)的多個(gè)連接而已。每個(gè)gh-ost都可以控制自己的節(jié)流,或者全部一次性控制它們的節(jié)流操作。
Going outside the server space
More to come as we make progress
異步設(shè)計(jì)缺點(diǎn)
增加流量
現(xiàn)有的工具都是通過(guò)觸發(fā)器來(lái)重播原表上的操作。gh-ost是通過(guò)自己來(lái)獲取原表操作,然后重播到gh-ost表上。gh-ost當(dāng)然更喜歡在從庫(kù)上獲取原表操作,然后在主庫(kù)上重播到gh-ost表上。這也意味著,主庫(kù)機(jī)器和從庫(kù)機(jī)器之間存在數(shù)據(jù)的傳輸。并且gh-ost使用的MySQL客戶(hù)端不支持壓縮功能, and so during a migration you can expect the full volume of a table to transfer on the wire。
增加代碼復(fù)雜性
基于觸發(fā)器同步方法的online DDL工具相對(duì)來(lái)說(shuō)代碼較少。大量的數(shù)據(jù)遷移是基于觸發(fā)器完成的。回滾,數(shù)據(jù)類(lèi)型以及cut-over階段都是由數(shù)據(jù)庫(kù)隱式處理的。gh-ost的異步方法讓它的代碼變的更復(fù)雜。它分別連接到主庫(kù)和從庫(kù),偽裝成從庫(kù),向主庫(kù)寫(xiě)入心跳事件,在從庫(kù)上讀取binlog事件并寫(xiě)入到主庫(kù)上,它還需要管理連接失敗,主從復(fù)制延遲等等。
因此,gh-ost擁有更大的代碼庫(kù)以及更復(fù)雜的異步并發(fā)邏輯。
總結(jié)
以上是生活随笔為你收集整理的[翻译]Triggerless design.md的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【NOIP】提高组2012 同余方程
- 下一篇: 移除单链表的倒数第N个节点