首頁  >  文章  >  資料庫  >  一文貫通MySQL日誌

一文貫通MySQL日誌

WBOY
WBOY轉載
2022-10-07 09:00:292335瀏覽

這篇文章為大家帶來了關於mysql的相關知識,其中主要介紹了關於日誌的相關問題,Mysql的日誌系統是Mysql保證無論何時崩潰資料都不會遺失的關鍵,下面一起來看一下,希望對大家有幫助。

一文貫通MySQL日誌

推薦學習:mysql影片教學

#Mysql的日誌系統是Mysql保證無論何時崩潰資料都不會遺失的關鍵

眾所周知Mysql是持久化的資料庫, 所有的資料都是持久化到硬碟中的, 保證資料不會遺失

Mysql保證資料不會遺失是從以下兩個方面來體現的

  • 能夠恢復到任意時刻的資料狀態

  • 無論在交易提交前或提交後崩潰都能保證資料不會遺失

事務過程中崩潰能夠恢復到交易提交前的狀態

交易提交後崩潰已提交的資料不會遺失

MySQL保證以上兩個點的關鍵就是透過undo log, redo log 和binlog 這三個日誌來實現的, 接下來將逐一介紹

undo log 回滾日誌

undo log是Mysql的回滾日誌, 儲存的是舊版的資料

#主要作用

儲存舊版的資料

# 配合Read View和隱藏欄位實作了Mysql的快照讀取

用於在交易執行失敗的時候回滾到事務開始前的版本

undo log 有什麼型別

undo log 有兩種類型

對於insert 指令, undo log 記錄的是新增的記錄的主鍵, 在回滾的時候根據undo log 中的主鍵去刪除對應的記錄即可

對於update / delete 指令, undo log 記錄的是被修改的記錄的舊資料

Mysql中的每一行資料都有一個最新修改目前資料行的事務id和回滾指標這兩個欄位, 當對資料行進行修改之後, undo log指標就會指向舊的這一行資料, 而新產生的這一行資料的回滾指標就會指向undo log指標目前指向的舊資料行

  • Mysql為了避免undo log指標修改指向的時候出現並發問題, 在修改之前會對undo log指標增加排他鎖以保證undo log的正確寫入

一文貫通MySQL日誌

undo log 什麼時候刪除

undo log是用來保證事務在未提交的時候可以順利回滾到事務開始前的狀態, 當事務提交之後undo log就失去作用了, 就需要被刪除

undo log是交由Mysql中的Purage 線程來負責刪除的, purage會定期檢查undo log中的deleted_bit 標誌, 這個標誌會在事務提交後被設定為true, purage 執行緒發現為true的記錄就會負責將其刪除

redo log 重做日誌

redo log是Mysql的實體日誌, 負責記錄某個資料頁執行了什麼樣的動作

redo log 的作用

  • 負責記錄提交的事務對資料的修改, 記錄的內容大概就是對x表的y頁z偏移做了a更新

  • #讓Mysql在提交交易的時候無需等待資料持久化磁碟, 只需要將redo log持久化到磁碟就可以了

  • 未清除的redo log的數量標識了未刷盤的髒頁數量

為什麼提交交易是選擇持久化redo log, 而不是持久化資料到磁碟

持久化資料到磁碟是隨機IO過程, 所以Mysql選擇將資料快取起來, 等待一個適當的時機將資料一次寫入磁碟, 減少IO

但是資料快取在記憶體中有遺失的風險, 所以Mysql選擇將redo log持久化

redo log是順序寫, 持久化的效率比隨機寫的效率要高, 並且redo log記錄了數據的變化情況, 只要redo log在就可以保證在Mysql重啟後恢復數據

#在InnoDB中, redo log是一個固定大小的類似循環隊列的存在, 每次寫入都從後面write pos的位置, 在持久化數據的時候就移動check point往前讀取

一文貫通MySQL日誌

#這樣設計的原因是因為redo log是防止Mysql崩潰後快取的髒頁資料遺失而存在的

當Mysql中的資料持久化到磁碟中後, 被持久化部分的redo log其實就沒有用了, 就可以騰出空間來記錄新的數據

undo log 和redo log 的區別

#

undo log記錄的是交易執行過程中舊資料的狀態, redo log記錄的是資料更新之後的狀態

redo log其實保障的是交易的持久性和一致性,而undo log則保障了交易的原子性

binlog 歸檔日誌

binlog是Mysql server層實作的日誌, 是所有引擎通用的

作用

binlog記錄的是mysql原始的語句邏輯, 並且是採用追加寫入的形式記錄的, 所以可以用來恢復mysql在任意時刻的資料庫資料狀態

所以叫binlog是歸檔日誌

同時binlog也是Mysql實作主從複製的依賴, 從函式庫透過從主函式庫複製binlog回放來同步主函式庫的資料狀態

#定義

先寫日誌到磁碟中, 再寫資料到磁碟中Mysql的寫操作不是立刻寫入到磁碟中的, 而是先寫日誌, 保證redo log和binlog都持久化到磁碟中再由後台執行緒選擇時機將資料持久化到硬碟的

為什麼要先寫日誌到磁碟中

##因為刷髒頁是一個隨機讀寫的過程, 持久化到磁碟中的速度肯定沒有redo log | binlog這些順序寫的速度快, 所以選擇先在內存中對數據進行修改, 再後期選擇時機異步持久化到磁碟中

所以在髒頁還未刷入磁碟中的這段時間就由redo log | binlog來保證數據的持久化, 防止斷電重啟等情況內存中的數據遺失

當髒頁滿的時候需要將髒頁寫入到磁碟再淘汰, 為何不全部淘汰掉下次使用的時候再透過redo log來復原呢

從效能方面考慮的, 如果每次從磁碟中讀取資料到記憶體都需要和redo log比對更新, 效率很低

MySQL刷髒頁寫入到磁碟保證了資料頁只要在內存中, 就肯定是當前最新的數據可以返回

如果內存中沒有數據只要從磁碟中讀取肯定能得到最新的正確數據, 而不用再去同redo log進行比對

binlog和redo log的寫入程序- WAL機制的基本保證

binlog和redo log都是將日誌寫入分割成三個程序寫入cache, write和sync

#在交易執行過程中會將binlog和redo log寫入到對應分配的快取中, 以便在交易提交的時候一次性寫入到磁碟中

在交易提交的時候會先進行write將資料寫入到作業系統的頁快取中, 此時資料還未真正寫入檔案, 但是已經是交由作業系統的快取來保管了, 如果此時Mysql進程崩潰這部分寫入的資料也不會遺失, 作業系統的核心執行緒會負責將這部分快取中的資料寫入磁碟

  • #但是如果作業系統崩潰了這部分資料就遺失了

#最後就是mysql手動呼叫sync將寫入在頁快取中的資料持久化到硬碟, 寫入完成後資料就是持久化成功了

最後的write和sync步驟mysql提供了對應的參數來控制寫入策略

redo log是透過innodb_flush_log_at_trx_commit來控制的

  • #設定為0 的時候,表示每次交易提交時都只是把redo log留在redo log的快取中

丟失風險最大

  • 設定為1 的時候,表示每次事務提交時都將redo log直接持久化到磁碟

丟失風險最小, 但是IO佔用大

  • 設定為2 的時候,表示每次事務提交時都只是把redo log寫到page cache

IO佔用居中, 將寫入到磁碟這個最佔用IO的過程交由作業系統來負責

binlog是透過參數sync_binlog來控制的

  • sync_binlog=0 的時候,表示每次提交交易都只write,不fsync

  • #sync_binlog=1 的時候,表示每次提交交易都會執行fsync

  • sync_binlog=N(N>1) 的時候,表示每次提交交易都write,但累積N 個交易後才fsync

兩階段日誌提交

#什麼是兩階段日誌提交

一文貫通MySQL日誌

將redo log日誌提交的過程分為prepare和commit這兩個階段, binlog日誌提交在這兩個階段中間

交易提交時redo log先提交後進入prepare狀態,然後binlog提交完成後redo log才能將日誌的狀態修改為commit已提交

為什麼需要兩階段日誌提交

和InnoDB引擎的回滾機制有關, InnoDB的redo log提交了事務就無法回滾了, 如果在redo log提交後binlog寫入失敗的話就會出現兩份不統一的情況

如果此時資料庫異常重啟的話要依據那一份來恢復資料就值得思考了, 所以才需要兩階段日誌提交

假設現在在時刻A資料庫崩潰的話, 因為binlog還未寫入, redo log還未提交, 所以重啟後事務會回滾, 兩份日誌依舊是統一狀態

如果是時間段B的話, 就需要對redo log的提交標誌進行判斷了, 在查詢redo log中是否有commit提交標誌, 如果有的話事務沒有問題, 直接提交

  • ##如果redo log中沒有對應交易的提交標誌的話會對binlog進行檢查

  • 如果binlog完整並且帶有commit標誌, 就會提交事務並在redo log後面補上commit標誌如果binlog不完整就回滾事務

這裡可以發現兩階段日誌提交中發生了崩潰是依據binlog來進行標準判斷的, 原因是因為主從複製是依據binlog來進行的

如果對兩份日誌都需要檢查完整性的話, 主庫掛掉切換到從庫的時間會變長, 以binlog為基準的話主庫掛了直接拿著binlog去從庫恢復數據即可, 無需檢查redo log的完整性

此外binlog是Mysql Server層的通用日誌, 這也是選擇binlog作為基準的原因

兩階段日誌提交的缺點

  • 磁碟IO次數高

在提交日誌的時候會有redo log和binlog對應的刷盤操作, IO次數高

  • 鎖定競爭激烈

為了保證多個交易提交的時候日誌的記錄和事務的提交順序是一致的, 會使用鎖來確保日誌提交的相對順序

但是在並發量大的情況下效能會變差

群組提交機制

群組提交機制的作用

當有躲過交易提交的時候, 將多個交易的日誌合併在一起去寫入, 減少磁碟IO操作

#群組提交機制的實作

群組提交機制將commit流程拆分成三個流程, 對每個流程都維護了一個佇列, 並且透過鎖定來保證交易的寫入順序

  • 分成三個階段分別加鎖可以減少鎖定粒度, 無需鎖定交易的整個提交過程

當佇列為空的時候第一個進入佇列的事務會成為後續進入的事務的領導者, 帶領後續事務完成接下來的階段操作

#階段一:

flush階段 : 多個事務按進入的順序將binlog從cache中寫入文件(不刷盤)

第一個進入flush階段的事務會作為領導者領導後面進入的事務

領導者事務會帶領所有的事務對redo log 進行一次write fsync, 也就是將redo log 寫入磁碟, 完成redo log 的propare階段

如果在這個階段Mysql崩潰了, 會在重啟後回滾這組事務

階段二:

sync : 對binlog檔案做fsync作業(將多個交易的binlog合併一起刷盤)

在flush階段將binlog寫入到binlog檔案後, 會等待一段時間再進行刷盤, 目的是組合更多事務的binlog一起刷盤減少消耗

#等待會有時間限制和最大事務限制, 滿足其中一個條件就會立刻對binlog進行刷磁碟

sync階段主要負責binlog的群組提交, 如果當前階段Mysql崩潰的話, 在重啟後可以透過redo log的刷盤記錄繼續完成交易提交

  • 因為此時binlog已經完成提交了, 所以可以根據redo log來繼續提交事務

#階段三:

commit : 對各個事務做InnoDB的commit操作

推薦學習:

mysql影片教學

以上是一文貫通MySQL日誌的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.im。如有侵權,請聯絡admin@php.cn刪除