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