Mysql日志-RedoLog、UndoLog和BinLog的关系捋顺
一條查詢語句的執行過程一般是經過連接器、分析器、優化器、執行器等功能模塊,最后到達存儲引擎。
那么,一條更新語句的執行流程又是怎樣的呢?以及MySQL可以恢復到半個月內任意一秒的狀態,這是怎樣做到的呢?
InnoDB是事務的存儲引擎,其通過Force Log at Commit機制實現事務的持久性,即當事務提交(COMMIT)時,必須先將該事務的所有日志寫入到重做日志文件進行持久化,待事務的 COMMIT操作完成才算完成。這里的日志是指重做日志,在InnoDB存儲引擎中,由兩部分組成,即redo log和undo log。redo log用來保證事務的持久性,undo log用來幫助事務回滾及Mvcc的功能。redo log基本上都是順序寫的,在數據庫運行時不需要對redo log的文件進行讀取操作。而undo log是需要進行隨機讀寫的。
WAL: Write-Ahead Logging
先寫日志,再寫磁盤。具體說,當有一條記錄需要更新的時候,InnoDB引擎就會先把記錄寫到redo log里面,并更新內存,這個時候更新計算完成了。同時InnoDB引擎會在在系統比較空閑的時候,將這個操作記錄更新到磁盤里。
WAL機制主要得益于兩個方面
1.redo log 和 binlog 都是順序寫,磁盤的順序寫比隨機寫速度要快;
2.組提交機制,可以大幅度降低磁盤的 IOPS 消耗。
只要redo log和binlog保證持久化到磁盤,就能確保MySQL異常重啟后,數據可以恢復。
REDO LOG(redo log保證事務的持久性)
redo log通常是物理日志,記錄的是數據頁的物理修改,而不是某一行或某幾行修改成怎樣怎樣,它用來恢復提交后的物理數據頁(恢復數據頁,且只能恢復到最后一次提交的位置)。
redo log包括兩部分:一是內存中的日志緩沖(redo log buffer),該部分日志是易失性的;二是磁盤上的重做日志文件(redo log file),該部分日志是持久的。
InnoDB的redo log是固定大小的,比如可以配置為一組4個文件,每個文件的大小是1GB,那么總共就可以記錄4GB的操作。從頭開始寫,寫到末尾就又回到開頭循環寫。
write pos是當前記錄的位置,一邊寫一邊后移,寫到第3號文件末尾后就回到0號文件開頭。checkpoint是當前要擦除的位置,也是往后推移并且循環的,擦除記錄前要把記錄更新到數據文件。
write pos和checkpoint之間的是還空著的部分,可以用來記錄新的操作。如果write pos追上checkpoint,表示日志滿了,這時候不能再執行新的更新,得停下來先擦掉一些記錄,把checkpoint推進一下。
有了redo log,InnoDB就可以保證即使數據庫發生異常重啟,之前提交的記錄都不會丟失,這個能力稱為crash-safe。
checkpoint機制
checkpoint:將緩沖池中的臟頁刷回到磁盤。
InnoDB存儲引擎內部,兩種checkpoint,分別為:
1.Sharp Checkpoint
2.Fuzzy Checkpoint
Sharp Checkpoint發生在數據庫關閉時,將所有的臟頁都刷新回磁盤,這是默認的工作方式,即參數:innodb_fast_shutdown=1。
在數據庫運行時,InnoDB存儲引擎內部采用Fuzzy Checkpoint,只刷新一部分臟頁。
Fuzzy Checkpoint的幾種情況:
1.MasterThread Checkpoint
異步刷新,每秒或每10秒從緩沖池臟頁列表刷新一定比例的頁回磁盤。異步刷新,即此時InnoDB存儲引擎可以進行其他操作,用戶查詢線程不會受阻。
2.FLUSH_LRU_LIST Checkpoint
InnoDB存儲引擎需要保證LRU列表中差不多有100個空閑頁可供使用。在InnoDB 1.1.x版本之前,用戶查詢線程(mysql5.6之后放在了單獨的進程Page Cleaner中進行)會檢查LRU列表是否有足夠的空間操作。如果沒有,根據LRU算法,溢出LRU列表尾端的頁,如果這些頁有臟頁,需要進行checkpoint。
設置參數:innodb_lru_scan_dept:控制LRU列表中可用頁的數量,該值默認1024
3.Async/Sync Flush Checkpoint
指重做日志不可用的情況,需要強制刷新頁回磁盤,此時的頁時臟頁列表選取的。
這種情況是保證重做日志的可用性,說白了就是,重做日志中可以循環覆蓋的部分空間太少了,換種說法,就是極短時間內產生了大量的redo log。
UNDO LOG(undo log保證事務的一致性)
重做日志記錄了事務的行為,可以很好地通過其對頁進行“重做”操作。但是事務有時還需要進行回滾操作,這時就需要undo。因此在對數據庫進行修改時, InnoDB存儲引擎不但會產生redo,還會產生一定量的undo。
redo存放在重做日志文件中,與redo不同,undo存放在數據庫內部的一個特殊段(segment)中,這個段稱為undo段(undo segment)。undo段位于共享表空間內。
除了回滾操作,undo的另一個作用是MVCC,即在 InnoDB存儲引擎中MVCC的實現是通過undo來完成。當用戶讀取一行記錄時,若該記錄已經被其他事務占用,當前事務可以通過undo讀取之前的行版本信息,以此實現非鎖定讀取。
undo log會產生redo log,也就是undo log的產生會伴隨著 redo log的產生,這是因為undo log也需要持久性的保護。
BINLOG
Server層也有自己的日志,稱為binlog(歸檔日志)。
binlog是MySQL數據庫的二進制日志,用于記錄用戶對數據庫操作的SQL語句((除了數據查詢語句)信息。
binlog的三種格式對比
statement、row、mixed(前兩種格式的混合)。
如果要在表中刪除一行數據的話,我們來看看這個delete語句的binlog是怎么記錄的。
statement->記錄的是sql原文
優點:不需要記錄每一條SQL語句與每行的數據變化,日志會比較少,減少了磁盤IO,提高性能。
缺點:在某些情況下會導致master-slave中的數據不一致
row格式:
運行這條delete命令產生了一個warning,原因是當前binlog設置的是statement格式,并且語句中有limit,所以這個命令可能是unsafe的。
在主庫執行這條SQL語句的時候,用的是索引a;而在備庫執行這條SQL語句的時候,卻使用了索引t_modified。
優點:不會出現某些特定情況下的存儲過程、或function、或trigger的調用和觸發無法被正確復制的問題。
缺點:會產生大量的日志,尤其是alter table的時候會讓日志暴漲。
REDO LOG 和 BINLOG 日志有以下三點不同:
1.redo log是InnoDB引擎特有的;binlog是MySQL的Server層實現的,所有引擎都可以使用。
2.redo log是物理日志,記錄的是“在某個數據頁上做了什么修改”;binlog是邏輯日志,記錄的是這個語句的原始邏輯,比如“給ID=2這一行的c字段加1 ”。
3.redo log是循環寫的,空間固定會用完;binlog是可以追加寫入的。“追加寫”是指binlog文件寫到一定大小后會切換到下一個,并不會覆蓋以前的日志。
[資料來源]
1.Mysql實戰45講-丁奇
2.MySQL技術內幕
總結
以上是生活随笔為你收集整理的Mysql日志-RedoLog、UndoLog和BinLog的关系捋顺的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: postman添加cookie
- 下一篇: Windows 上配置Docker De