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