InnoDB元件結構:
buffer pool : 緩衝池,快取磁碟的資料
redo log buffer :記錄對緩衝池的操作,根據策略寫入磁碟防止宕機但事務已經提交而丟失資料
undo log :當對緩衝池的資料進行修改時,在事務未提交的時候都可以進行回滾,將舊值寫入 undo 紀錄檔檔案便於回滾,此時緩衝池的資料與磁碟中的不一致,是髒資料
假設現在有一條更新語句:
update users set name = 'lisi' where id = 1
需要更新到資料庫,InnoDB會執行哪些操作呢?
首先,InnoDB會判讀緩衝池裡是否存在 id = 1 這條資料,如果不存在則從磁碟中載入到緩衝池中,而且還會對這行資料加獨佔鎖,防止多個sql同時修改這行資料。
假設 id = 1 這條資料name原來的值 name = 'zhangsan',現在我們要更新為 name = 'lisi' , 那麼我們就需要把舊值name='zhangsan'和id=1這些資訊寫入到undo紀錄檔檔案中。
對於熟悉資料庫的同學來說都瞭解事務的概念,在事務未提交之前,所有操作都有可能進行回滾,即可以把 name = 'lisi' 回滾到 name = 'zhangsan',所以將更新前的值寫到undo紀錄檔檔案。
在undo紀錄檔檔案寫入完畢之後,便開始更新記憶體中的這條資料。把 id = 1 的 name = 'zhangsan' 更新為 name = 'lisi'。這時記憶體中的資料已經更新完畢,但磁碟上的還沒有變化,此時出現了不一致的髒資料。
這時可能有一個疑問,萬一事務提交完成,但MySQL服務宕機了,而記憶體中的資料還沒寫入到磁碟,是不是會造成資料丟失而造成sql執行資料前後不一致?
在InnoDB結構中,有一個 redo log buffer 緩衝區存放redo紀錄檔,所謂redo紀錄檔,例如 把id=1,name='zhangsan'修改為name='lisi' 便是一條紀錄檔。
但這時redo log buffer 還僅僅存在記憶體中,沒能實現MySQL宕機後的資料恢復。
其實並沒有影響,事務沒有提交,意味著執行沒有成功,就算MySQL崩潰或者宕機後,記憶體中的 buffer pool 和 redo log buffer 修改過的資料都會丟失,也並不影響資料前後的一致性。如果事務提交失敗,那資料庫的資料更加不會改變。
在提交事務時,redo日記會根據策略實現把redo紀錄檔從 redo log buffer 裡寫入磁碟。策略通過 innoDB_flush_log_at_trx_commit 來設定。
innoDB_flush_log_at_trx_commit的引數為0,就算事務提交後,也不會把redo紀錄檔寫入磁碟。MySQL宕機後會記憶體中的資料會丟失。
innoDB_flush_log_at_trx_commit的引數為1,事務提交後,redo紀錄檔會從記憶體刷入磁碟,只要事務提交成功,redo log 就必然存在磁碟裡。
此時就算buffer pool 的資料沒有刷進磁碟,也可以從redo log 中得知修改過哪些資料,MySQL宕機重新啟動後,可以從redo紀錄檔中恢復修改的資料。
innoDB_flush_log_at_trx_commit的引數為2,事務提交後,redo log 僅僅停留在 os cache 中,還沒刷進磁碟,萬一此時服務宕機了。那麼os cache 中的資料也會丟失,即使事務提交成功,也會造成資料丟失。
看完這幾種相信為了保證資料安全,引數為1是最佳策略。
binlog其實是屬於MySQL Server 的紀錄檔檔案,而在這出提出是因為與redo log有著很大的關聯。
1) biglog 與 redo log的區別
redo log:記錄的是偏物理性質重做紀錄檔,比如 「對哪個資料頁中的什麼記錄,做了哪些修改」
binlog:偏向於邏輯性的紀錄檔,如:「對users表中的id=10的一行資料做了更新操作,更新以後的值是什麼」
2) 提交事務的時候同時寫入binlog
在執行更新的同時,innoDB與執行器一直在互動,包括載入資料到緩衝池,寫入undo紀錄檔檔案,更新記憶體資料,寫redo紀錄檔和刷入磁碟等。而對binlog的寫入也是由執行器執行。
其中 1、2、3、4步驟為執行更新語句做的事,而 5、6是提交事務開始做的事。
3) binlog紀錄檔刷盤策略分析
sync_binlog引數控制binlog的刷盤策略
sync_ binlog預設值是0,提交事務後,會把binlog紀錄檔存在 os cache 中,MySQL宕機後會造成os cache中資料的丟失
sync_binlog 值為1,提交事務後,把binlog紀錄檔直接刷入磁碟中。
4) 基於binlog 和 redo log 完成事務的提交
binlog寫入磁碟後,會把binlog紀錄檔檔案所在的位置和檔名稱都寫入redo log紀錄檔檔案中,同時在redo log紀錄檔檔案裡寫入一個commit標記。
5) commit 標記有什麼意義?
commit 標記意義著保持redo log 和 binlog 紀錄檔一致。如果在步驟5或者步驟6,事務提交開始,MySQL宕機了,redo log 中並沒有commit標記,都算事務提交失敗。
意味著 commint 標記是事務最終提交成功。
髒資料刷入磁碟是由後臺IO執行緒隨機刷入磁碟的。
這時候考慮到,在刷入磁碟之前,MySQL宕機怎麼辦?這時候,事務已經提交成功,redo log 中也有commit標記,就算宕機了,重新啟動後,也會根據redo紀錄檔檔案把資料更新到記憶體中,等待IO執行緒的刷盤。
通過更新語句執行分析之後,瞭解到InnoDB儲存引擎中包含了 buffer pool 緩衝池、redo log buffer 緩衝區等快取資料,undo、reod log等紀錄檔檔案,同時也有MySQL Server 的紀錄檔檔案。
在執行更新語句的時候,會修改buffer pool、寫undo紀錄檔檔案、 寫redo log buffer等操作;提交事務時,會將redo log 刷盤,binlog刷盤,寫入binlog檔名稱和位置,寫入commit標記,最後等待IO執行緒將buffer pool的髒資料隨機刷盤。
推薦學習:
以上就是完全掌握MySQL原理篇之InnoDB儲存引擎架構設計的詳細內容,更多請關注TW511.COM其它相關文章!