日志系統(tǒng): redo log(重做日志)和binlog(歸檔日志)。
重要的日志模塊:redo log
MySQL WAL(Write-Ahead-Logging)關(guān)鍵點是先寫日志,再寫磁盤。
當(dāng)更新數(shù)據(jù)時,InnoDB引擎就會先把記錄寫到redo log里面,并更新內(nèi)存,這個是否更新就算完成,在合適的時候,將記錄寫入到磁盤里面。
redo log的標(biāo)記:write pos 是當(dāng)前記錄的位置,一邊寫一邊后移;checkpoint是當(dāng)前要擦出的位置,也是往后移動推移并且循環(huán)的,
擦除記錄前要把記錄更新到數(shù)據(jù)文件。
有了redo log,InnoDB就可以保證即使數(shù)據(jù)庫發(fā)生異常重啟,之前提交的記錄都不會丟失,這個能力成為crash-safe。
重要的日志模塊:binlog
Server層有自己的日志,稱為binlog。redo log是InnoDB引擎特有的日志。
剛開始時,MySQL自帶的引擎是MyISAM,但是MyISAM沒有crash-safe的能力,binlog日志只能用于歸檔。
redo log與binlog的區(qū)別:
- redo log是InnoDB引擎特有的;binlog是MySQL Server層實現(xiàn)的,所有引擎都可以使用。
- redo log是物理日志,記錄的是在某個數(shù)據(jù)頁上做了什么修改;binlog是邏輯日志,記錄的是這個語句的原始邏輯。
- redo log是循環(huán)寫的,空間固定會用完;binlog是可以追加寫入的。追加寫入是指binlog文件寫到一定大小后會切換到下一個,并不會覆蓋以前的日志。
更新流程:
- 執(zhí)行器先找引擎得到修改的記錄,如果在內(nèi)存中,直接返回;如果沒有在內(nèi)存中,從磁盤讀取內(nèi)存,然后在返回。
- 執(zhí)行器拿到數(shù)據(jù)后,修改之后,然后通過引擎將數(shù)據(jù)寫入內(nèi)存。
- 引擎將數(shù)據(jù)更新到內(nèi)存中,同時將這個更新操作記錄到redo log里面,此時redo log處于prepare狀態(tài),然后告知執(zhí)行器執(zhí)行完成了,隨時可以提交事務(wù)。
- 執(zhí)行器生成這個操作的binlog,并把binlog寫入磁盤。
- 執(zhí)行器調(diào)用引擎的提交事務(wù)接口,引擎把剛剛寫入的redo log改成commit狀態(tài),更新完成。
兩階段
binlog會記錄所有的邏輯操作,并且是采用"追加寫"的形式。
由于redo log和binlog是兩個獨立的邏輯,如果不用兩階段,就會出現(xiàn)問題
- 先寫redo log后寫binlog:redo log寫完,binlog沒有寫完,MySQL進(jìn)程異常重啟。系統(tǒng)崩潰之后,恢復(fù)的數(shù)據(jù)為更新后的數(shù)據(jù),binlog恢復(fù)的數(shù)據(jù)是原先的數(shù)據(jù)。
- 先寫binlog 后寫redo:binglog寫完之后crash,事務(wù)無效,值沒有變化,由于redo log還沒寫,通過binlog恢復(fù)的數(shù)據(jù)就多一個事務(wù)出來,與原庫不同。
redo log用于保證crash-safe能力。innodb_flush_log_at_trx_commit這個參數(shù)設(shè)置為1的時候,表示每次事務(wù)的redo log都直接持久化到磁盤。
這樣可以保證MySQL異常重啟之后數(shù)據(jù)不丟失。
sync_binlog這個參數(shù)設(shè)置為1時,表示每次事務(wù)的binlog都持久化到磁盤。這樣保證MySQL異常重啟之后binlog不丟失。
binlog有兩種模式,statement格式的記sql語句,row格式會記錄行的內(nèi)容,記兩條,更新前和更新后都有。
redo只是完成了prepare,binlog失敗,事務(wù)本身就會回滾,所以這個庫里面status的值是0。