概述 undo log(回滾日志):是 Innodb 存儲引擎層生成的日志,實現(xiàn)了事務中的原子性,主要用于事務回滾和 MVCC。 redo log(重做日志):是 Innodb 存儲引擎層生成的日志,實現(xiàn)了事務中的持久性,主要用于掉電等故障恢復; binlog (歸檔日志):是 Server 層生成
邏輯格式的日志,在執(zhí)行 undo 的時候,僅僅是將數(shù)據(jù)從邏輯上恢復至事務之前的狀態(tài),而不是從物理頁面上操作實現(xiàn)的,這一點是不同于redo log 的。
每當 InnoDB 引擎對一條記錄進行操作(修改、刪除、新增)時,要把回滾時需要的信息都記錄到 undo log 里,比如:
事務開始之前 ,MySQL 會先記錄更新前的數(shù)據(jù)到 undo log 日志文件里面,當事務回滾時,可以利用 undo log 來進行回滾。同時undo 也會產(chǎn)生 redo 來保證undo log的可靠性。
undo log 和數(shù)據(jù)頁的刷盤策略是一樣的,都需要通過 redo log 保證持久化。產(chǎn)生undo日志的時候,同樣會伴隨類似于保護事務持久化機制的redolog的產(chǎn)生。
buffer pool 中有 undo 頁,對 undo 頁的修改也都會記錄到 redo log。redo log 會每秒刷盤,提交事務時也會刷盤,數(shù)據(jù)頁和 undo 頁都是靠這個機制保證持久化的,具體看下面內(nèi)容。
物理格式的日志,記錄的是物理數(shù)據(jù)頁面的修改的信息,其 redo log 是順序寫入redo log file 的物理文件中去的。同時,在內(nèi)存修改 Undo log 后,也需要記錄undo log對應的 redo log。
redo log 和 undo log 區(qū)別:
事務開始之后就產(chǎn)生redo log,redo log的落盤并不是隨著事務的提交才寫入的,而是在事務的執(zhí)行過程中,便開始寫入redo log文件中。
事務提交之前發(fā)生了崩潰,重啟后會通過 undo log 回滾事務,事務提交之后發(fā)生了崩潰,重啟后會通過 redo log 恢復事務,如下圖:
redo log 要寫到磁盤,數(shù)據(jù)也要寫磁盤,為什么要多此一舉?
寫入 redo log 的方式使用了追加操作, 所以磁盤操作是順序寫,而寫入數(shù)據(jù)需要先找到寫入位置,然后才寫到磁盤,所以磁盤操作是隨機寫。磁盤的「順序寫 」比「隨機寫」 高效的多,因此 redo log 寫入磁盤的開銷更小。
實際上, 執(zhí)行一個事務的過程中,產(chǎn)生的 redo log 也不是直接寫入磁盤的,因為這樣會產(chǎn)生大量的 I/O 操作,而且磁盤的運行速度遠慢于內(nèi)存。
redo log有一個緩存區(qū) Innodb_log_buffer,Innodb_log_buffer 的默認大小為 16M,每當產(chǎn)生一條 redo log 時,會先寫入到 redo log buffer,后續(xù)再持久化到磁盤。
然后會通過以下三種方式將innodb log buffer的日志刷新到磁盤:
因此redo log buffer的寫盤,并不一定是隨著事務的提交才寫入redo log文件的,而是隨著事務的開始,逐步開始的。
即使某個事務還沒有提交,Innodb存儲引擎仍然每秒會將redo log buffer刷新到redo log文件。
這一點是必須要知道的,因為這可以很好地解釋再大的事務的提交(commit)的時間也是很短暫的。
兩個 redo 日志的文件名叫 :ib_logfile0 和 ib_logfile1。
redo log文件組是以循環(huán)寫的方式工作的, InnoDB 存儲引擎會先寫 ib_logfile0 文件,當 ib_logfile0 文件被寫滿的時候,會切換至 ib_logfile1 文件,當 ib_logfile1 文件也被寫滿時,會切換回 ib_logfile0 文件;相當于一個環(huán)形。
因此,如果 write pos 追上了 checkpoint,就意味著 redo log 文件滿了,這時 MySQL 不能再執(zhí)行新的更新操作,也就是說 MySQL 會被阻塞
binlog 有 3 種格式類型,分別是 STATEMENT(默認格式)、ROW、 MIXED,區(qū)別如下:
注意:不同的日志類型在主從復制下除了有動態(tài)函數(shù)的問題,同樣對對更新時間也有影響。一般來說,數(shù)據(jù)庫中的update_time都會設置成ON UPDATE CURRENT_TIMESTAMP,即自動更新時間戳列。在主從復制下,
如果日志格式類型是STATEMENT,由于記錄的是sql語句,在salve端是進行語句重放,那么更新時間也是重放時的時間,此時slave會有時間延遲的問題;
如果日志格式類型是ROW,這是記錄行數(shù)據(jù)最終被修改成什么樣了,這種從庫的數(shù)據(jù)是與主服務器完全一致的。
事務 提交的時候 ,一次性將事務中的sql語句(一個事物可能對應多個sql語句)按照一定的格式記錄到binlog中。
binlog 文件是記錄了所有數(shù)據(jù)庫表結構變更和表數(shù)據(jù)修改的日志,不會記錄查詢類的操作,比如 SELECT 和 SHOW 操作。
這里與redo log很明顯的差異就是binlog 是追加寫,寫滿一個文件,就創(chuàng)建一個新的文件繼續(xù)寫,不會覆蓋以前的日志,保存的是全量的日志。redo log 是循環(huán)寫,日志空間大小是固定,全部寫滿就從頭開始,保存未被刷入磁盤的臟頁日志。
也就是說,如果不小心整個數(shù)據(jù)庫的數(shù)據(jù)被刪除了,只能使用 bin log 文件恢復數(shù)據(jù)。因為redo log循環(huán)寫會擦除數(shù)據(jù)。
MySQL 的主從復制依賴于 binlog ,也就是記錄 MySQL 上的所有變化并以二進制形式保存在磁盤上。復制的過程就是將 binlog 中的數(shù)據(jù)從主庫傳輸?shù)綇膸焐稀?
這個過程一般是異步的,也就是主庫上執(zhí)行事務操作的線程不會等待復制 binlog 的線程同步完成。
MySQL 集群的主從復制過程如下:
在刷盤時機上與redolog不一樣,redolog即使事務沒提交,也可以每隔1秒就刷盤。但是一個事務的 binlog 是不能被拆開的,因此無論這個事務有多大(比如有很多條語句),也要保證一次性寫入。如果一個事務的 binlog 被拆開的時候,在備庫執(zhí)行就會被當做多個事務分段自行,這樣就破壞了原子性,是有問題的。
bin log日志與redo log類似,也有對應的緩存,叫 binlog cache。事務提交的時候,再把 binlog cache 寫到 binlog 文件中。
MySQL提供一個 sync_binlog 參數(shù)來控制數(shù)據(jù)庫的 binlog 刷到磁盤上的頻率:
顯然,在MySQL中系統(tǒng)默認的設置是 sync_binlog = 0,也就是不做任何強制性的磁盤刷新指令,這時候的性能是最好的,但是風險也是最大的。因為一旦主機發(fā)生異常重啟,還沒持久化到磁盤的數(shù)據(jù)就會丟失。
而當 sync_binlog 設置為 1 的時候,是最安全但是性能損耗最大的設置。因為當設置為 1 的時候,即使主機發(fā)生異常重啟,最多丟失一個事務的 binlog,而已經(jīng)持久化到磁盤的數(shù)據(jù)就不會有影響,不過就是對寫入性能影響太大。
如果能容少量事務的 binlog 日志丟失的風險,為了提高寫入的性能,一般會 sync_binlog 設置為 100~1000 中的某個數(shù)值。
事務提交后,redo log 和 binlog 都要持久化到磁盤,但是這兩個是獨立的邏輯,可能出現(xiàn)半成功的狀態(tài),這樣就造成兩份日志之間的邏輯不一致。如下:
兩階段提交把單個事務的提交拆分成了 2 個階段,分別是「準備(Prepare)階段」和「提交(Commit)階段」
事務的提交過程有兩個階段,就是將 redo log 的寫入拆成了兩個步驟:prepare 和 commit,中間再穿插寫入binlog,具體如下:
總的來說就是,事務提交后,redo log變成prepare 階段,再寫入binlog,返回成功后redo log 進入commit 階段。
當優(yōu)化器分析出成本最小的執(zhí)行計劃后,執(zhí)行器就按照執(zhí)行計劃開始進行更新操作。
具體更新一條記錄 UPDATE t_user SET name = 'xiaolin' WHERE id = 1; 的流程如下:
Java面試題專欄 已上線,歡迎訪問。
那么可以私信我,我會盡我所能幫助你。
本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權,請發(fā)郵件[email protected]
湘ICP備2022002427號-10 湘公網(wǎng)安備:43070202000427號© 2013~2025 haote.com 好特網(wǎng)