程式設計師必備介面測試偵錯工具:
推薦學習:
Mysql的紀錄檔系統是Mysql保證無論何時崩潰資料都不會丟失的關鍵
眾所周知Mysql是持久化的資料庫, 所有的資料都是持久化到硬碟中的, 保證資料不會丟失
Mysql保證資料不會丟失是從以下兩個方面來體現的
能夠恢復到任意時刻的資料狀態
無論在事務提交前還是提交後崩潰都能保證資料不丟失
事務過程中崩潰能夠恢復到事務提交前的狀態
事務提交後崩潰已提交的資料不會丟失
MySQL保證以上兩個點的關鍵就是通過 undo log, redo log 和 binlog 這三個紀錄檔來實現的, 接下來將逐一介紹
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的正確寫入
undo log 什麼時候刪除
undo log是用於保證事務在未提交的時候可以順利回滾到事務開始前的狀態, 當事務提交之後undo log就失去作用了, 就需要被刪除
undo log是交由Mysql中的 Purage 執行緒來負責刪除的, purage會定期檢查undo log中的deleted_bit 標誌, 這個標誌會在事務提交後被設定為true, purage 執行緒發現為true的記錄就會負責將其刪除
redo log是Mysql的物理紀錄檔, 負責記錄某個資料頁執行了什麼樣的操作
redo log 的作用
負責記錄提交的事務對資料的修改, 記錄的內容大概就是對x表的y頁z偏移做了a更新
讓Mysql在提交事務的時候無需等待資料持久化磁碟, 只需要將redo log持久化到磁碟就可以了
未清除的redo log的數量標識了未刷盤的髒頁數量
持久化資料到磁碟是隨機IO過程, 所以Mysql選擇將資料快取起來, 等待一個合適的時機將資料一次性寫入磁碟, 減少IO
但是資料快取在記憶體中有丟失的風險, 所以Mysql選擇將redo log持久化
redo log是順序寫, 持久化的效率比隨機寫的效率要高, 並且redo log記錄了資料的變化情況, 只要redo log在就可以保證在Mysql重新啟動後恢復資料
在InnoDB中, redo log是一個固定大小的類似迴圈佇列的存在, 每次寫入都從後面write pos的位置, 在持久化資料的時候就移動check point往前讀取
這樣設計的原因是因為redo log是防止Mysql崩潰後快取的髒頁資料丟失而存在的
當Mysql中的資料被持久化到磁碟中後, 被持久化部分的redo log其實就沒有用了, 就可以騰出空間來記錄新的資料
undo log 和 redo log 的區別
undo log記錄的是事務執行過程中舊資料的狀態, redo log記錄的是資料更新之後的狀態
redo log其實保障的是事務的永續性和一致性,而undo log則保障了事務的原子性
binlog是Mysql server層實現的紀錄檔, 是所有引擎通用的
作用
binlog記錄的是mysql原始的語句邏輯, 並且是採用追加寫入的形式記錄的, 所以可以用於恢復mysql在任意時刻的資料庫資料狀態
同時binlog也是Mysql實現主從複製的依賴, 從庫通過從主庫中複製binlog回放來同步主庫的資料狀態
定義
先寫紀錄檔到磁碟中, 再寫資料到磁碟中Mysql的寫操作不是立刻寫入到磁碟中的, 而是先寫紀錄檔, 保證redo log和binlog都持久化到磁碟中再由後臺執行緒選擇時機將資料持久化到硬碟的
為什麼要先寫紀錄檔到磁碟中
因為刷髒頁是一個隨機讀寫的過程, 持久化到磁碟中的速度肯定沒有redo log | binlog這些順序寫的速度快, 所以選擇先在記憶體中對資料進行修改, 再後期選擇時機非同步持久化到磁碟中
所以在髒頁還未刷入磁碟中的這段時間就由redo log | binlog來保證資料的持久化, 防止斷電重新啟動等情況記憶體中的資料丟失
當髒頁滿的時候需要將髒頁寫入到磁碟再淘汰, 為何不全部淘汰掉下次使用的時候再通過redo log來恢復呢
從效能方面考慮的, 如果每次從磁碟中讀取資料到記憶體都需要和redo log比對更新, 效率很低
MySQL刷髒頁寫入到磁碟保證了資料頁只要在記憶體中, 就肯定是當前最新的資料可以返回
如果記憶體中沒有資料只要從磁碟中讀取肯定能得到最新的正確資料, 而不用再去同redo log進行比對
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
什麼是兩階段紀錄檔提交
將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紀錄檔的詳細內容,更多請關注TW511.COM其它相關文章!