緩沖池 buffer pool
- 會把一些磁盤上的數據加載到該內存當中
- 查詢數據的時候不從磁盤查,從該內存里查
undo log
- 邏輯日志,可以認為當delete一條記錄時,undo log中會記錄一條對應的insert記錄,反之亦然,當update一條記錄時,它記錄一條對應相反的update記錄
- 用於數據回滾
- 實現mvcc
redo log
- 存儲引擎層日志
- 物理日志(類似於“對哪個數據頁中的什么記錄,做了個什么修改”)
- 記錄對數據做了什么修改,防止已提交事務的數據丟失。因為數據不是實時刷盤的,數據是在buffer pool當中,如果數據庫宕機了並且buffer pool中的數據還沒有刷盤,修改過的數據就丟失了,redo log解決這一問題
- redo log buffer是redo log的緩沖區,數據做了什么修改,首先會寫入到redo log buffer中,再刷盤寫入redo log中
binlog
- 歸檔日志,屬於mysql server層,不屬於存儲引擎層
- 邏輯性日志(類似於“對users表中的id=10的一行數據做了更新操作,更新以后的值是什么”)
事務還沒有提交,mysql宕機了怎么辦?
- 事務沒有提交,mysql宕機,buffer pool和redo log buffer中的數據都會丟失,數據庫返回異常,提示事務失敗
- 磁盤上的數據沒有任何變化,不影響
redo log刷盤策略
- 當提交事務的時候,redo log buffer里的數據會根據一定規則刷到磁盤上
- 通過innodb_flush_log_at_trx_commit參數來配置
- 0 提交事務的時候,不立即把 redo log buffer 里的數據刷入磁盤文件的,而是依靠 InnoDB 的主線程每秒執行一次刷新到磁盤。此時可能你提交事務了,結果 mysql 宕機了,然后此時內存里的數據全部丟失
- 1 提交事務的時候,就必須把 redo log 從內存刷入到磁盤文件里去,只要事務提交成功,那么 redo log 就必然在磁盤里了
- 2 提交事務的時候,把 redo 日志寫入磁盤文件對應的 os cache 緩存里去,而不是直接進入磁盤文件,可能 1 秒后才會把 os cache 里的數據寫入到磁盤文件里去。此時mysql宕機,數據不會丟失;如果機器宕機,數據會丟失
binlog刷盤策略
- 當提交事務的時候,binlog也會刷到磁盤上去
- 通過sync_binlog參數來配置
- 0 默認值。事務提交后,將二進制日志寫入了操作系統緩沖,若操作系統宕機則會丟失部分二進制日志
- 1 事務提交后,將二進制文件寫入磁盤並立即執行刷新操作,相當於是同步寫入磁盤,不經過操作系統的緩存
執行一條更新sql語句,存儲引擎執行流程
- 把該行數據從磁盤加載到buffer pool中
- 對該行數據進行加鎖
- 寫undo log
- 在buffer pool當中更新數據
- 把所作的修改寫入到redo log buffer當中
- 准備提交事務redolog刷盤
- 准備提交事務binlog刷盤
- 把binlog的文件名和位置寫入commit標記,commit標記寫入redolog中,事務才算提交成功;否則不會成功
commit標記的意義
- redo log刷盤成功,binlog還沒刷盤,數據庫宕機,沒有commit標記寫到redo log中,事務判定為失敗。因為redolog中有這次更新日志,binlog中沒有這次更新日志,會出現數據不一致問題
- redo log刷盤成功,binlog刷盤成功,commit標記還沒來得及寫入redo log中,數據庫宕機,同樣判定事務提交失敗
- commit寫入redo log,才能判定事務成功;因為此時,redo log中有這次更新記錄,binlog也有這次更新記錄,redo log和binlog保持了一致
內存(buffer pool)中更新過臟數據什么時候刷盤?
- 后台io線程有時間會把內存buffer pool中更新過的臟數據(因為更新過,和磁盤上的數據不一樣,所以叫臟數據)刷回到磁盤上,哪怕這時候mysql宕機,也沒有關系,可通過redo log和binlog恢復數據到內存中,io線程有時間再把數據刷盤
執行更新sql語句存儲引擎執行流程總結
- 執行階段
- 數據加載到內存,寫undo log,更新內存中數據,寫redo log buffer
- 事務提交階段
- redo log和binlog刷盤,commit標記寫入redo log中
- 最后
- 后台io線程隨機把內存中臟數據刷到磁盤上
文章和圖片參考 救火隊長mysql