作者:魏新平雪隧,知數(shù)堂第5期MySQL實戰(zhàn)班學員漓糙,第10期MySQL優(yōu)化班學員卿闹,現(xiàn)任職助教捺宗。
Describing safe, blocking, atomic, pure-mysql cut-over phase
原文鏈接:https://github.com/github/gh-ost/issues/82
作者:shlomi-noach
我們提供的方式是基于兩個數(shù)據(jù)庫連接的对蒲。假如我們的連接是C10钩蚊,C20。應用的連接是C1..C9,C11..C19,C21..C29齐蔽。
C1..C9在 tbl 上進行正常的dml操作:INSERT, UPDATE, DELETE
C10: CREATE TABLE tbl_old (id int primary key) COMMENT='magic-be-here'
C10: LOCK TABLES tbl WRITE, tbl_old WRITE
C11..C19,新進來的對tbl的操作两疚,由于C10的鎖,會被阻塞
C20: RENAME TABLE tbl TO tbl_old, ghost TO tbl
由于C10加的鎖含滴,也會被阻塞住诱渤。但是當鎖被釋放后,會比C1..C9,C11..C19先執(zhí)行谈况。
C21..C29勺美,新進來對tbl的dml操作還是會被阻塞住
C10: 檢測C20的rename操作是否存在(在show processlist當中尋找rename關鍵字)
C10: DROP TABLE tbl_old
大家還是被鎖住,什么嚴重的事情都不會發(fā)生碑韵,除了刪除這個tbl_old表赡茸。
C10:UNLOCK TABLES
BAM(象聲詞,不知道怎么翻譯祝闻,尷尬占卧,只能意會不能言傳)!RENAME操作會先執(zhí)行联喘,ghost表會被重命名為tbl表华蜒,然后C1..C9,C11..C19,C21..C29會直接在新的tbl表上執(zhí)行豁遭。
一些解釋:
創(chuàng)建tbl_old是為了阻止C20的RENAME操作
當一個連接擁有對某個表的WRITE鎖的時候叭喜,可以執(zhí)行drop該表的操作。
不管是誰先被阻塞蓖谢,當一個表的INSERT/UPDATE/DELETE操作和RENAME操作同時被阻塞的情況下捂蕴,RENAME操作總是會先執(zhí)行。
假如上面的過程當中C10或者C20失敗了闪幽,會發(fā)生什么呢
先說結論啥辨,就算失敗了,不會發(fā)生災難性的事情盯腌,也不需要回滾溉知。
假如C10在CREATE tbl_old的時候發(fā)生錯誤,直接退出
假如C10在LOCK tbl,tbl_old的語句發(fā)生錯誤,直接退出着倾,表不會被鎖住,app可以繼續(xù)對tbl進行dml操作
假如C10在C20剛要執(zhí)行RENAME操作的時候連接直接掛了
WRITE鎖會被釋放掉燕少,C1..C9卡者,C11..C19可以繼續(xù)在原表執(zhí)行
C20會因為tbl_old表的存在而RENAME失敗
整個操作失敗,但是沒什么嚴重的問題產(chǎn)生客们,只是一些語句被阻塞了很短的一段時間崇决。我們會重試整個cut-over流程。
假如C10在C20被阻塞后掛了底挫,發(fā)生的事情和上面的流程差不多恒傻。鎖釋放,C20失斀ǖ恕(因為tbl_old的存在),其他所有的被阻塞的語句會正常在原來的表上執(zhí)行
假如C20在C10 DROP表之前掛了盈厘,我們會捕捉到錯誤并按計劃執(zhí)行。刪除表并且釋放鎖官边。沒什么嚴重的事情發(fā)生沸手,頂多一些語句被阻塞一會。我們需要重新嘗試整個流程注簿。
假如C20在C10 DROP后釋放鎖之前掛了契吉,和上面發(fā)生的事情一樣。
假如C10和C20都掛了诡渴。鎖被釋放捐晶,RENAME失敗,C1..C9,C11..C19,C21..C29阻塞的語句會正常在tbl上執(zhí)行妄辩。
不管發(fā)生什么事情惑灵,在操作的最后我們都會檢查ghost表是否還存在。假如不在了恩袱,那就說明操作成功了泣棋。整個流程可以被看成是原子性的。
順便說一下畔塔,如果操作失敗了潭辈,可能會存在table_old表需要我們手動刪除澈吨。其實刪不刪除都無所謂把敢。如果你看不慣可以刪除掉,不刪除掉的話谅辣,也沒關系修赞,下一次操作就不用重建了。
對應用的影響
在流程開始之后到流程結束的時間里,不管是成功還是失敗柏副,應用的連接都會被阻塞住勾邦。成功的話,阻塞的語句會被執(zhí)行到新表割择,失敗的話眷篇,阻塞的語句會執(zhí)行到舊表。
對復制的影響
復制只會看到RENAME操作荔泳,binlog是不會記錄lock語句的蕉饼。所以復制看到的是原子性的兩表交換,不會有表不存在的情況玛歌。
針對網(wǎng)友的一些提問
為啥要用兩個連接進行這么麻煩的流程昧港?
因為一個連接在獲取tbl的鎖的情況下,無法進行rename操作(至少現(xiàn)在不能)支子。但是作者說他會說服工程師在MYSQL的下個版本當中實現(xiàn)创肥,就不需要這么麻煩的操作了。(下面代碼測試是我測試的译荞,不是作者的)
admin@localhost [test] 11:39:32>lock table t write;
Query OK, 0 rows affected (0.00 sec)
admin@localhost [test] 11:39:36>rename table t to t10;
ERROR 1192 (HY000): Can't execute the given command because you have active locked tables or an active transaction
admin@localhost [test] 11:39:48>select @@version;
+---------------+
| @@version |
+---------------+
| 5.7.22-22-log |
+---------------+
1 row in set (0.00 sec)
為啥要鎖原來的表和創(chuàng)建的tbl_old表瓤的?
由于異步的應用binlog的日志,如果不鎖住原表的話吞歼,可能會存在一些語句未被應用圈膏。為啥要鎖住tbl_old表呢,作者自己也不太記得了篙骡,因為時間的原因稽坤,畢竟是回憶三年前的事情了,不過肯定是有原因的糯俗。