自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

賜我白日夢發表於2021-03-15

Hi,大家好!我是白日夢!本文是MySQL專題的第 26 篇。

下文還是白日夢以自導自演的方式,圍繞“組提交”展開本話題。看看你能抗到第幾問吧

換一種寫作風格,自導自演面試現場!感覺這樣還是比較有趣的,歡迎大家訂閱我的MySQL專題,公眾號首發!持續更新中~

點選閱讀原文,格式會好看一點哦~

點選閱讀原文,格式會好看一點哦~

點選閱讀原文,格式會好看一點哦~

公眾號後臺回覆:資料庫 可以參與抽獎活動,3本《MySQL技術內幕-InnoDB儲存引擎》

歡迎關注白日夢,公眾號首發!持續連載中


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

庫尼奇瓦自導自演的面試現場之--你竟然不瞭解MySQL的組提交?,同學,聽說你上一面表現的還可以,這一面要不我們繼續?自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


嗯,好啊!自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

好,你瞭解MySQL的兩階段提交不?說說看自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


嗯,瞭解。自導自演的面試現場之--你竟然不瞭解MySQL的組提交? 簡單來說兩階段提交就是將事務提交分成兩部分,經過這兩步處理後,我們稱這個事務被提交了。


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

嗯,那兩個階段呢?你說說看!自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


可以看下面這張圖:我們當執行commit命令時,會按照如下進行。


第一階段:寫redo log,並標識上prepare。

-- 中間穿插寫binlog --

第二階段:寫redo log,完成事務的最終提交。

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

嗯,那你知不知道為什麼事務的提交要分成兩個階段?自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


嗯,你看上圖中的兩階段是redolog-prepare、redolog-commit這兩個階段,然後在這兩個階段中又寫了binlog。自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


這個redolog主要提供的能力是對事務進行rollback、並且redolog是儲存引擎層面記錄的日誌。自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


而binlog的作用是方面我們進行資料的備份以及MySQL叢集主從之間的資料同步使用,並且binlog是MySQL上層,也就是Server層面記錄的日誌。自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


綜上:MySQL的兩階段提交是為了保證redolog、binlog兩者在邏輯上的一致性。才能進一步保證。事務的回滾、資料備份、已經MySQL叢集之間的資料才是安全可靠的


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

嗯,那你能不能舉個例子,更直觀的告訴我,redolog、binlog兩者在邏輯一致的必要性以及用途?自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


嗯,好啊!自導自演的面試現場之--你竟然不瞭解MySQL的組提交?,比如這個例子:

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


在這個例子中,進行完第三步之後,沒來得及寫binlog,然後主庫就掛了,事務也沒來得及提交。


這時主庫從新啟動之後會選擇將這個事務丟棄,因為如果它將事務提交了,從庫們相對主庫來說就少了這條資料,造成了主從資料不一致問題


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?



嗯,在看這個例子自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

在這個例子中主庫當機前雖然也沒有完成對事務對提交,但是它已經寫了redolog-prepare、還寫了binlog,binlog寫完之後很可能從庫已經收到這個最新的binlog,並且將這個binlog中的資料回放到自己身上了。


所以主庫重新啟動之後呢,會選擇按照redolog將當機前的事務狀態從記憶體中恢復出來,也就是說把記憶體中的快取頁改成髒資料頁,然後提交事務


這時主庫如果不提交事務,那主庫就比從庫少了一條資料,同時會造成主從不一致的情況出現。


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

白日夢補充:
本小節我們重點看MySQL的組提交,而不是兩階段提交,想更多的兩階段提交的故事,可以點選檢視白日夢寫的:全網最牛X的兩階段提交筆記

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

嗯,你說的沒錯自導自演的面試現場之--你竟然不瞭解MySQL的組提交?。我有個問題哈,你看你畫的這張圖,事務提交時寫了好幾次日誌。


而且一般我們線上的資料庫都有這兩個配置

# 該引數控制binlog的落盤時機# 設定為1表示當事務被提交時將binlog落盤# 設定為0表示由檔案系統自己控制binlog的落盤時機sync_binlog=1# 該引數控制redolog的落盤時機  # 設定為1表示當事務被提交時將redolog落盤innodb_flush_log_at_trx_commit=1

那你有沒有想過:即使寫日誌是磁碟的順序IO速度極快,即使固態硬碟的效能很?,那終究也還是在跟磁碟打交道啊!自導自演的面試現場之--你竟然不瞭解MySQL的組提交? 


那你是否瞭解MySQL針對這個現狀有什麼優化的落地實現方案嗎?


我提醒你一下,比如:組提交


哦!我還真瞭解一些group commit的概念!


在MySQL早期的設計中,所謂的組提交,也就是 group commit 實際上提交的是group commit redolog。(而不是binlog)


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

而且MySQL寫redolog並不是產生一條redolog就寫一條redo log的!而是以redo log block為單位寫入磁碟,而且在redo log block 之上還有個redo log buffer的概念自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


總結來說就是:寫redolog要分成2大步:


Step1:將redolog寫入記憶體buffer中。

Step2:將redolog fsync到磁碟中。


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

白日夢補充:
點選檢視白日夢的redolog筆記:傳說中的redo log到底是什麼?


點選檢視白日夢筆記:fsync系統呼叫到底是什麼?


而組提交的概念是說:當進行fsync時,一下子將多個事務日誌寫入到磁碟中。自導自演的面試現場之--你竟然不瞭解MySQL的組提交? 通俗來講,假如說你寫一次磁碟需要10ms,如果我們按條每個redolog都寫一次磁碟的話,10條redolog就需要100ms的耗時。


現在我們有了組提交,可以一次fsync將10條redolog一次磁碟IO就持久化到磁碟中,耗時可能也就十幾ms的樣子。效能是有所提升的。自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

嗯,你說的沒錯自導自演的面試現場之--你竟然不瞭解MySQL的組提交?!而且我還注意到了你說的一個細節問題,你上面說,原來的group commit針對的是redolog,而不是binlog。這個緣由你能展開說一下嗎?自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?.....


好的,這個問題就得從binlog的作用說起了。MySQL不可能無緣無故的就寫binlog,它之所以記錄binlog是因為它想獲取到寫binlog帶給它的紅利。


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

那什麼紅利呢?其實前面說了很多遍了,主要的紅利就是:binlog給了MySQL搭建叢集的可能性,以及資料備份的能力。自導自演的面試現場之--你竟然不瞭解MySQL的組提交? 


而且預設情況下binlog是不會開啟的。其實說白了,如果你不需要binlog帶給我們的能力,比如你偏偏就不需要做資料的備份、或者搭建叢集,那麼其實你直接使用預設配置不開啟binlog就好了。此時的兩階段提交也不復存在。自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


但是事實並不是這樣的,線上的資料庫都是以叢集的形式存在、並且也需要資料備份。也就是說binlog是開啟的狀態。事務的提交也是走的兩階段提交。自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

 那,回到我們組提交的話題來看,其實在早期的MySQL中,並沒有一個很好的機制讓 組提交和兩階段提交共存的!


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

嗯,為什麼這麼說?自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


嗯,其實你大概一想就知道為什麼了。根本原因就在用 binlog是MySQL的上層(Server層)記錄的。而redolog是下層的儲存引擎層記錄的。自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


所以你突然整一個redolog的組提交出來,那兩階段提交怎麼辦?自導自演的面試現場之--你竟然不瞭解MySQL的組提交?你為了效能哐當一下將記憶體中的redolog全落盤了,但是兩階段提交中每一步寫日誌的順序是有要求的呀。它倆正好相違背。自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


所以其實在InnoDB1.2版本之前,當開啟binlog使用兩階段提交時,組提交會失效....自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

嗯,你說的沒錯。那後來沒有比較好的解決方式呢?


嗯,其實是有的自導自演的面試現場之--你竟然不瞭解MySQL的組提交?,早在2010年facebook的MySQL技術組,Percona公司就給出瞭解決方案。後來由MariaDB資料庫的開發人員Kristian Nielsen完成了最終的完美解決方案。


所以如果你使用的是MySQL5.6或者更好的版本,它就在兩階段提交的概念上,還加持上了組提交的buff,效能相對之前有了很多的提升。自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

嗯,那你可否大概說一下如何實現的?


嗯嗯,想了解它的具體的實現可以看這張圖:

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

我稍微解讀一下這張圖:總體來說分為三個部分,分別是Flush階段、Sync階段、Commit階段


並且它引入了一個新的概念:佇列,事務按提交的順序進入佇列中,佇列有先進先出的概念,最先進入佇列的事務被成為leader


在Flush階段就是將當前佇列中的所有事務的binlog統一寫入記憶體中,Sync就是將當前佇列中的所有事務的binlog通過一次fsync統一寫入到磁碟中。(相當於批量將binlog落盤)


最後的commit階段,由佇列中的leader根據一定的順序呼叫儲存引擎層的事務提交,完成兩階段的第二階段提交。事務結束...


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

 這時就會形成一個比較理想的狀態,當一組事務發生Commit時,新的事務可以去Flush。讓整個過程中的組提交不斷的生效。


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

嗯,你繼續說自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


但是如果每次佇列中都只有一個事務,那可能會導致效能還不如之前沒有這種佇列的設計自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

嗯,你繼續往下說。


還有就是我還了解關於組提交相關的一個控制引數

binlog_max_flush_queue_time

這個引數可以控制Flush階段的等待時間。預設情況下該引數設定為0,推薦設定也為0。


如果我們不把它設定為0,意思就是說想讓佇列中的事務攢一攢,攢多了再統一處理,想獲取到一次fsync將大量日誌落盤帶來的速度快的紅利。但是這樣同樣會導致事務的響應時間變慢。


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

嗯!你說的沒問題自導自演的面試現場之--你竟然不瞭解MySQL的組提交?,整體上看你的回答的還可以!


我沒有問題了,你還有什麼想問我的嗎?自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


沒有問題了,感謝大佬百忙抽空來給我面試!自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


自導自演的面試現場之--你竟然不瞭解MySQL的組提交?

哈哈,客氣!好好準備,期待你下一面優秀的表現自導自演的面試現場之--你竟然不瞭解MySQL的組提交?


推薦閱讀

  1. MySQL的修仙之路,圖文談談如何學MySQL、如何進階!(已釋出)
  2. 面前突擊!33道資料庫高頻面試題,你值得擁有!(已釋出)
  3. 大家常說的基數是什麼?(已釋出)
  4. 講講什麼是慢查!如何監控?如何排查?(已釋出)
  5. 對NotNull欄位插入Null值有啥現象?(已釋出)
  6. 能談談 date、datetime、time、timestamp、year的區別嗎?(已釋出)
  7. 瞭解資料庫的查詢快取和BufferPool嗎?談談看!(已釋出)
  8. 你知道資料庫緩衝池中的LRU-List嗎?(已釋出)
  9. 談談資料庫緩衝池中的Free-List?(已釋出)
  10. 談談資料庫緩衝池中的Flush-List?(已釋出)
  11. 瞭解髒頁刷回磁碟的時機嗎?(已釋出)
  12. 用十一張圖講清楚,當你CRUD時BufferPool中發生了什麼!以及BufferPool的優化!(已釋出)
  13. 聽說過表空間沒?什麼是表空間?什麼是資料表?(已釋出)
  14. 談談MySQL的:資料區、資料段、資料頁、資料頁究竟長什麼樣?瞭解資料頁分裂嗎?談談看!(已釋出)
  15. 談談MySQL的行記錄是什麼?長啥樣?(已釋出)
  16. 瞭解MySQL的行溢位機制嗎?(已釋出)
  17. 說說fsync這個系統呼叫吧! (已釋出)
  18. 簡述undo log、truncate、以及undo log如何幫你回滾事物! (已釋出)
  19. 我勸!這位年輕人不講MVCC,耗子尾汁! (已釋出)
  20. MySQL的崩潰恢復到底是怎麼回事? (已釋出)
  21. MySQL的binlog有啥用?誰寫的?在哪裡?怎麼配置 (已釋出)
  22. MySQL的bin log的寫入機制 (已釋出)
  23. 刪庫後!除了跑路還能幹什麼?(已釋出)
  24. 自導自演的面試現場,趣學資料庫的10種檔案(已釋出)
  25. 大型面試現場:一條update sql執行都經歷什麼?(已釋出)
  26. 大型翻車現場:如何實現記錄存在的話就更新,如果記錄不存在的話就插入。(已釋出)

最後,歡迎關注白日夢的公號哦~

換一種寫作風格,自導自演面試現場!感覺這樣還是比較有趣的,歡迎大家訂閱我的MySQL專題,公眾號首發!持續更新中~

相關文章