当前位置:网站首页>MySQL實戰優化高手04 借著更新語句在InnoDB存儲引擎中的執行流程,聊聊binlog是什麼?

MySQL實戰優化高手04 借著更新語句在InnoDB存儲引擎中的執行流程,聊聊binlog是什麼?

2022-07-06 10:04:00 辦公模板庫 素材蛙

1、上一講思考題解答:redo日志刷盤策略的選擇建議

先給大家解釋一下上一講的思考題,我給大家的一個建議,其實對於redo日志的三種刷盤策略,我們通常建議是設置1

也就是說,提交事務的時候,redo日志必須是刷入磁盤文件裏的。

這樣可以嚴格的保證提交事務之後,數據是絕對不會丟失的,因為有redo日志在磁盤文件裏可以恢複你做的所有修改。

如果要是選擇0的話,可能你提交事務之後,mysql宕機,那麼此時redo日志沒有刷盤,導致內存裏的redo日志丟失,你提交的事務更新的數據就丟失了;

如果要是選擇2的話,如果機器宕機,雖然之前提交事務的時候,redo日志進入os cache了,但是還沒進入磁盤文件,此時機器宕機還是會導致os cache裏的redo日志丟失。

所以對於數據庫這樣嚴格的系統而言,一般建議redo日志刷盤策略設置為1,保證事務提交之後,數據絕對不能丟失。

2MySQL binlog到底是什麼東西?

接著我們來看看MySQL binlog到底是個什麼東西?

實際上我們之前說的redo log,他是一種偏向物理性質的重做日志,因為他裏面記錄的是類似這樣的東西,對哪個數據頁中的什麼記錄,做了個什麼修改

而且redo log本身是屬於InnoDB存儲引擎特有的一個東西。

binlog叫做歸檔日志,他裏面記錄的是偏向於邏輯性的日志,類似於users錶中的id=10的一行數據做了更新操作,更新以後的值是什麼

binlog不是InnoDB存儲引擎特有的日志文件,是屬於mysql server自己的日志文件。

3、提交事務的時候,同時會寫入binlog

所以其實我們上一講講到,在我們提交事務的時候,會把redo log日志寫入磁盤文件中去。然後其實在提交事務的時候,我們同時還會把這次更新對應的binlog日志寫入到磁盤文件中去,如下圖所示。

             

大家可以在這個圖裏看到一些變動,就是我把跟InnoDB存儲引擎進行交互的組件加入了之前提過的執行器這個組件,他會負責跟InnoDB進行交互,包括從磁盤裏加載數據到Buffer Pool中進行緩存,包括寫入undo日志,包括更新Buffer Pool裏的數據,以及寫入redo log bufferredo log刷入磁盤,寫binlog,等等。

實際上,執行器是非常核心的一個組件,負責跟存儲引擎配合完成一個SQL語句在磁盤與內存層面的全部數據更新操作。

而且我們在上圖可以看到,我把一次更新語句的執行,拆分為了兩個階段,上圖中的1234幾個步驟,其實本質是你執行這個更新語句的時候幹的事。

然後上圖中的56兩個步驟,是從你提交事務開始的,屬於提交事務的階段了。

4binlog日志的刷盤策略分析

對於binlog日志,其實也有不同的刷盤策略,有一個sync_binlog參數可以控制binlog的刷盤策略,他的默認值是0此時你把binlog寫入磁盤的時候,其實不是直接進入磁盤文件,而是進入os cache內存緩存。

所以跟之前分析的一樣,如果此時機器宕機,那麼你在os cache裏的binlog日志是會丟失的,我們看下圖的示意

             
如果要是把sync_binlog參數設置為1的話,那麼此時會强制在提交事務的時候,把binlog直接寫入到磁盤文件裏去,那麼這樣提交事務之後,哪怕機器宕機,磁盤上的binlog是不會丟失的,如下圖所示

            

5、基於binlogredo log完成事務的提交

當我們把binlog寫入磁盤文件之後,接著就會完成最終的事務提交,此時會把本次更新對應的binlog文件名稱和這次更新的binlog日志在文件裏的比特置,都寫入到redo log日志文件裏去,同時在redo log日志文件裏寫入一個commit記。

在完成這個事情之後,才算最終完成了事務的提交,我們看下圖的示意。

           

6、最後一步在redo日志中寫入commit標記的意義是什麼?

這時候肯定有同學會問了,最後在redo日志中寫入commit標記有什麼意義呢?

說白了,他其實是用來保持redo log日志與binlog日志一致的。

我們來舉個例子,假設我們在提交事務的時候,一共有上圖中的567三個步驟,必須是三個步驟都執行完畢,才算是提交了事務。那麼在我們剛完成步驟5的時候,也就是redo log剛刷入磁盤文件的時候,mysql宕機了,此時怎麼辦?

這個時候因為沒有最終的事務commit標記在redo日志裏,所以此次事務可以判定為不成功。不會說redo日志文件裏有這次更新的日志,但是binlog日志文件裏沒有這次更新的日志,不會出現數據不一致的問題。

如果要是完成步驟6的時候,也就是binlog寫入磁盤了,此時mysql宕機了,怎麼辦?

同理,因為沒有redo log中的最終commit標記,因此此時事務提交也是失敗的。

必須是在redo log中寫入最終的事務commit標記了,然後此時事務提交成功,而且redo log裏有本次更新對應的日志,binlog裏也有本次更新對應的日志redo logbinlog完全是一致的。

7、後臺IO線程隨機將內存更新後的髒數據刷回磁盤

現在我們假設已經提交事務了,此時一次更新“update users set name='xxx' where id=10”,他已經把內存裏的buffer pool中的緩存數據更新了,同時磁盤裏有redo日志和binlog日志,都記錄了把我們指定的“id=10”這行數據修改了“name='xxx'”

此時我們會思考一個問題了,但是這個時候磁盤上的數據文件裏的“id=10”這行數據的name字段還是等於zhangsan這個舊的值啊!

所以MySQL有一個後臺的IO線程,會在之後某個時間裏,隨機的把內存buffer pool中的修改後的髒數據給刷回到磁盤上的數據文件裏去,我們看下圖:

             

當上圖中的IO線程把buffer pool裏的修改後的髒數據刷回磁盤的之後,磁盤上的數據才會跟內存裏一樣,都是name=xxx這個修改以後的值了!

在你IO線程把髒數據刷回磁盤之前,哪怕mysql宕機崩潰也沒關系,因為重啟之後,會根據redo日志恢複之前提交事務做過的修改到內存裏去,就是id=10的數據的name修改為了xxx,然後等適當時機,IO線程自然還是會把這個修改後的數據刷到磁盤上的數據文件裏去的

8、基於更新數據的流程,總結一下InnoDB存儲引擎的架構原理

大家通過一次更新數據的流程,就可以清晰地看到,InnoDB存儲引擎主要就是包含了一些buffer poolredo logbuffer等內存裏的緩存數據,同時還包含了一些undo日志文件,redo日志文件等東西,同時mysql server自己還有binlog日志文件。

在你執行更新的時候,每條SQL語句,都會對應修改buffer pool裏的緩存數據、寫undo日志、寫redo log buffer個步驟;

但是當你提交事務的時候,一定會把redo log刷入磁盤,binlog刷入磁盤,完成redo log中的事務commit標記;最後後臺的IO線程會隨機的把buffer pool裏的髒數據刷入磁盤裏去。

9、思考題:執行更新操作的時候,為什麼不能執行修改磁盤上的數據?

好了,今天的文章接近尾聲,咱們再來思考一個問題:

為什麼MySQL在更新數據的時候,要大費周章的搞這麼多事情,包括buffer poolredo logundo logbinlog、事務提交、髒數據。引入了一大堆的概念,有複雜的流程和步驟。

為什麼他反而最關鍵的修改磁盤裏的數據,要通過IO線程不定時的去執行?

為什麼他不幹脆直接就每次執行SQL語句,直接就更新磁盤裏的數據得了?

原网站

版权声明
本文为[辦公模板庫 素材蛙]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/187/202207060907389741.html