被面試官問住了,MySQL兩階段提交是什麼鬼?
前言
MySQL通過兩階段提交的機制,保證了redo log和bin log的邏輯一致性,進而保證了資料的不丟失以及主從庫的資料一致。
而說起兩階段提交,就不得不先介紹一下redo log和bin log。
redo log
redo log即重做日誌,是InnoDB引擎特有的一種日誌(有的面試官經常問到這一點)。
redo log主要做什麼呢?
以更新資料為例,我們知道,MySQL的資料是儲存在磁碟上的,如果每一次更新資料,都去磁碟定址找到要更新的資料,進行更新操作的話,這個IO成本是非常高的。
如果是固態硬碟還好,如果是機械硬碟,那麼MySQL的更新效能根本無法滿足我們的業務需要。
所以,MySQL採用了一種叫做WAL的技術,Write-Ahead Logging。
當更新資料時,將更新操作(即某個資料頁上做了什麼修改)先寫到redo log裡面,然後更新記憶體,這個更新操作就算完成了。MySQL會在伺服器空閒的時候,把redo log的操作記錄重新整理到磁盤裡,以保持資料的一致性。
需要注意的是,redo log雖然也是磁碟上的一個檔案,但是由於操作是順序寫,所以效能是非常高的。
當然了,redo log也是有大小上限的,不可能無限制的寫入。
以上圖為例,配置了4個redo log,write pos就是代表當前記錄寫到什麼位置了,而check point表示一個推進點,它會不斷的前移,做擦除資料的操作,以保證redo log可以不斷的寫入。
當然,擦除資料之前,會把redo log的記錄重新整理到磁碟。
通過redo log,可以保證即使MySQL發生異常重啟,資料也不會丟失(因為redo log是物理日誌,可以進行重放),這個特性就叫做crash-safe。
bin log
bin log是MySQL Server提供的一種日誌,叫做歸檔日誌,所有引擎都可以使用bin log。
那bin log和redo log的區別是什麼呢?
1,這兩種日誌的提供者不同:bin log是由MySQL Server提供的,redo log是InnoDB引擎特有的。
2,redo log主要記錄的是某個資料頁做了什麼修改,bin log記錄的是語句的原始邏輯,比如更新了某一行的某個欄位。
3,redo log是迴圈寫的,資料會被覆蓋。bin log是追加寫,一個檔案寫滿,就寫下一個檔案。
兩階段提交
介紹完了redo log和bin log,我們再看一下他們兩者是如何配合完成兩階段提交的。
上圖就是一個更新資料的流程,可以看到,在更新一條資料之前,MySQL會先將資料載入到記憶體,然後更新記憶體,開始寫redo log。
此時,redo log處於prepare狀態,等到bin log寫完之後,再提交事務,這一條記錄的更新操作就算完成了。
redo log prepare -> 寫bin log -> redo log commit,這個流程就叫做兩階段提交。
下面我們分析一下,採用兩階段提交的好處。
情景一,redo log處於prepare狀態時,如果寫bin log失敗了,那麼更新失敗,此時redo log沒有commit,bin log也沒有記錄,兩者的狀態是一致的,沒有問題。
情景二,redo log處於prepare狀態時,寫bin log成功,但是宕機導致commit失敗了。此時bin log產生了記錄,redo log沒有寫入成功,資料暫時不一致。
但是不用擔心,當MySQL重啟時,會檢查redo log中處於prepare狀態的記錄。在redo log中,記錄了一個叫做XID的欄位,這個欄位在bin log中也有記錄,MySQL會通過這個XID,如果在bin log中找到了,那麼就commit這個redo log,如果沒有找到,說明bin log其實沒有寫成功,就放棄提交。
通過這樣的機制,保證了redo log和bin log的一致性。
總結
之所以MySQL中既存在redo log,又存在bin log,這是因為bin log是MySQL Server提供的一種歸檔日誌,其本身並不具備crash-safe能力。而redo log本身不具備歸檔能力,他是一種迴圈寫的日誌。
MySQL通過將這兩種日誌整合起來,並通過兩階段提交的機制,保證了資料的一致性。
寫文不易,感謝您的點贊和關注。