MySQL update執行流程到 redo log深刻理解

前面咱們分析過一個查詢語句的執行流程,而且解釋了執行過程當中涉及的模塊。一條查詢語句通常是通過鏈接器、分析器、優化器、執行器等功能模塊,最後到達存儲引擎。老鐵們能夠點擊連接 查詢語句在 MySQL 如何執行 學習上篇內容。數據庫

此次,咱們來深刻學習一條更新語句在 MySQL 中的執行流程。經過此文咱們能夠充分了解 什麼是 Redo Log緩存

表結構建立

首先咱們先建立一張表,只有主鍵 ID,以及 int 類型字段 c。架構

create table T(ID int primary key, c int);

如今咱們要更新一條數據,語句以下:學習

update T set c=c+1 where ID=2;

更新語句其實也跟查詢語句的流程相似,只不過多了 redo log、undo log 以及 binlog 日誌。優化

未命名文件.png

上一篇查詢語句的執行流程咱們說過,在一個表上有更新的時候,跟這個表有關的查詢緩存會失效,因此這條語句會把整個 T 表的緩存結果都清空。這也是爲什麼咱們不建議使用查詢緩存的緣由。spa

帳本與記帳板

假如您當了小超市老闆,天然會有一個帳本記錄交易記錄,可是可能還要一個賒帳記錄。由於村裏有個姑娘叫小芳,長得美麗又善良。有時候會到你這裏白嫖,額,不是,是賒帳。你先把記錄寫在小粉板上,等夜深人靜的時候就把粉板的數據同步到歸檔的帳本中。固然粉板也有滿的時候,因此當粉板滿了就要對帳寫入帳本中,插件

因此,若是有人要來賒帳,或者還帳的時候,一般有兩種作法:設計

  1. 直接把帳本翻出來,把此次的賒帳加上去或者扣除。
  2. 先在粉板上記下此次的賬,等打烊後再把帳本翻出來覈算。

在生意忙的時候,咱們確定選擇後者,由於前者操做太麻煩了。首先,你得找到這我的的賒帳總額那條記錄。你想一想,密密麻麻幾十頁,掌櫃要找到那個名字,可 能還得帶上老花鏡慢慢找,找到以後再拿出算盤計算,最後再將結果寫回到帳本上。這個時候小芳來賒帳,等半天。之後還怎麼約小芳到小樹林呢?3d

MySQL 中也有這個問題,若是每一次操做都要寫進磁盤,而後磁盤也要找到對應的記錄,而後再更新。整個過程的 IO 成本,查詢成本都很高,爲了解決這個問題,MySQL的設計者就用了相似小超市老闆粉板的思路來提高更新效率。日誌

而粉板和帳本配合的整個過程,其實就是 MySQL 裏常常說到的 WAL 技術,WAL 的全稱是Write-Ahead Logging,它的關鍵點就是先寫日誌,再寫磁盤,也就是先寫粉板,等不忙的時候再寫帳本。

redo log

首先咱們要明確的是binlog 日誌是在 server 層的,而redo logInnoDB 特有的。

當有一條記錄須要更新的時候,InnoDB引擎就會先把記錄寫到 redo log(粉板)中,並更新內存,這個時候就算完成了。同時 引擎會在適當的時候將這個記錄更新到磁盤裏,而更新每每是系統比較閒的時候,這就是打樣之後掌櫃作的事情。

相似的,InnoDB 的 redo log 是固定大小的,好比能夠配置爲一組 4 個文件,每一個文件的大小是 1GB,那麼這塊「粉板」總共就能夠記錄 4GB 的操做。從頭開始寫,寫到末尾就又回到開頭循環寫,以下面這個圖所示。

redolog buff.png

write pos 是當前記錄的位置,一邊寫一邊後移,寫到第 3 號文件末尾後就回到 0 號文件開頭。checkpoint 是當前要擦除的位置,也是日後推移而且循環的,擦除記錄前要把記錄更新到數據文件。

write pos 和 checkpoint 之間的是「粉板」上還空着的部分,能夠用來記錄新的操做。若是 write pos 追上 checkpoint,表示「粉板」滿了,這時候不能再執行新的更新,得停下來先擦掉一些記錄,把 checkpoint 推動一下。

有了 redo log,InnoDB 就能夠保證即便數據庫發生異常重啓,以前提交的記錄都不會丟失,這個能力稱爲crash-safe

要理解 crash-safe 這個概念,能夠想一想咱們前面賒帳記錄的例子。只要賒帳記錄記在了粉板上或寫在了帳本上,以後即便掌櫃忘記了,好比忽然停業幾天,恢復生意後依然能夠經過帳本和粉板上的數據明確賒帳帳目。

binlog

MySQL 的總體架構其實有兩塊:一塊是 Server 層,還有一塊是 引擎層,負責存儲相關。前面咱們提到的 redo logInnoDB 引擎持有的,而 Server 層也有本身的日誌,叫 binlog(歸檔日誌)。

那爲什麼會有兩份日誌呢?

由於最開始 MySQL 裏並無 InnoDB 引擎。MySQL 自帶的引擎是 MyISAM,可是 MyISAM 沒有 crash-safe 的能力(由於是 Server 層與引擎層是兩個獨立的模塊),binlog 日誌只能用於歸檔。而 InnoDB 是另外一個公司以插件形式引入 MySQL 的,既然只依靠 binlog 是沒有 crash-safe 能力的,因此 InnoDB 使用另一套日誌系統——也就是 redo log 來實現 crash-safe 能力。

假如只有 binlog,當 Server 層 binlog 日誌寫完後 引擎層尚未同步到磁盤就斷電了。這個時候重啓後 binlog 記錄了更新操做,可是引擎層並無寫入磁盤中就致使了從庫使用該 binlog 同步數據不一致。

redo log、 binlog 的 差別

  1. redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 層實現的,全部引擎均可以使用。
  2. redo log 是物理日誌,記錄的是「在某個數據頁上作了什麼修改」;binlog 是邏輯日誌,記錄的是這個語句的原始邏輯,好比「給 ID=2 這一行的 c 字段加 1 」。
  3. redo log 是循環寫的,空間固定會用完;binlog 是能夠追加寫入的。「追加寫」是指 binlog 文件寫到必定大小後會切換到下一個,並不會覆蓋之前的日誌。

Update 語句執行流程

有了對兩個日誌的概念理解,咱們就能夠繼續理解執行器與 InnoDB 引擎執行 update 語句時的內部流程。

  1. Server 層的執行器先調用引擎取出 ID=2 這一行。ID 是主鍵,引擎直接用樹搜索找到這一行。若是 ID=2 這一行所在的數據頁原本就在內存中,就直接返回給執行器;不然,須要先從磁盤讀入內存,而後再返回。
  2. 執行器拿到數據把這個值 + 1,獲得新一行的數據,再調用存儲引擎接口寫入這行新數據。
  3. InnoDB 引擎將這行數據更新到內存中,同時將這個更新操做所影響的頁日誌記錄到 redo log 中,此時日誌處於 prepare 狀態,而後會告知 執行器完成了,隨時能夠提交事務。
  4. 執行器生成這個操做的 binlog ,並把 binlog 寫入磁盤。
  5. 執行器繼續調用引擎的的提交事務接口,引擎收到請求就把剛剛寫入的 redo log 的狀態改爲提交(commit),更新完成。

最後三步看上去有點「繞」,將 redo log 的寫入拆成了兩個步驟: prepare 和 commit,這就是"兩階段提交"。

以下圖所示,綠色表明執行器執行,白色表明 InnoDB 引擎執行:

update流程.png

update流程

兩階段提交

爲何必須有「兩階段提交」呢?這是爲了讓兩份日誌之間的邏輯一致。要說明這個問題,咱們得從文章開頭的那個問題提及:怎樣讓數據庫恢復到半個月內任意一秒的狀態?

前面咱們說過了,binlog 會記錄全部的邏輯操做,而且是採用「追加寫」的形式。若是你的 DBA 承諾說半個月內能夠恢復,那麼備份系統中必定會保存最近半個月的全部 binlog,同時系統會按期作整庫備份。這裏的「按期」取決於系統的重要性,能夠是一天一備,也能夠是一週一備。

當須要恢復到指定的某一秒時,好比某天下午兩點發現中午十二點有一次誤刪表,須要找回數據,那你能夠這麼作:

  1. 首先,找到最近的一次全量備份,若是你運氣好,可能就是昨天晚上的一個備份,從這個備份恢復到臨時庫;
  2. 而後,從備份的時間點開始,將備份的 binlog 依次取出來,重放到中午誤刪表以前的那個時刻。

因爲 redo log 和 binlog 是兩個獨立的邏輯,若是不用兩階段提交,要麼就是先寫完 redo log 再寫 binlog,或者採用反過來的順序。咱們看看這兩種方式會有什麼問題。(會形成數據不一致)

仍然用前面的 update 語句來作例子。假設當前 ID=2 的行,字段 c 的值是 0,再假設執行 update 語句過程當中在寫完第一個日誌後,第二個日誌尚未寫完期間發生了 crash,會出現什麼狀況呢?

先寫 redo log 後寫 binlog

假如在引擎 寫完 redo log 後,bin log 沒有寫完,異常重啓,依然能夠根據 redo log 日誌把數據恢復,可是 binlog 沒有記錄這個語句。 因此從庫 經過 binlog 同步數據就致使沒有把這個這行數據同步過來,丟失了這個事務操做形成數據不一致。

先寫 binlog 再寫 redo log

若是寫完 binlog 後 崩潰,因爲 redo log 尚未寫,崩潰恢復後這個事務無效,可是 binlog 卻有記錄。從庫根據 這個 binlog 日誌就會致使多處一個事務,與主庫不一致。

簡單說,redo log 和 binlog 均可以用於表示事務的提交狀態,而兩階段提交就是讓這兩個狀態保持邏輯上的一致。(敲黑板了同窗們)
關注公衆號 JavaStorm 解鎖更多精彩
二維碼.jpg

相關文章
相關標籤/搜索