前言

數(shù)據(jù)庫(kù)系統(tǒng)與文件系統(tǒng)最大的區(qū)別在于數(shù)據(jù)庫(kù)能保證操作的原子性,一個(gè)操作要么不做要么都做,即使在數(shù)據(jù)庫(kù)宕機(jī)的情況下,也不會(huì)出現(xiàn)操作一半的情況,這個(gè)就需要數(shù)據(jù)庫(kù)的日志和一套完善的崩潰恢復(fù)機(jī)制來(lái)保證。本文仔細(xì)剖析了InnoDB的崩潰恢復(fù)流程,代碼基于5.6分支。

基礎(chǔ)知識(shí)

lsn: 可以理解為數(shù)據(jù)庫(kù)從創(chuàng)建以來(lái)產(chǎn)生的redo日志量,這個(gè)值越大,說明數(shù)據(jù)庫(kù)的更新越多,也可以理解為更新的時(shí)刻。此外,每個(gè)數(shù)據(jù)頁(yè)上也有一個(gè)lsn,表示最后被修改時(shí)的lsn,值越大表示越晚被修改。比如,數(shù)據(jù)頁(yè)A的lsn為100,數(shù)據(jù)頁(yè)B的lsn為200,checkpoint lsn為150,系統(tǒng)lsn為300,表示當(dāng)前系統(tǒng)已經(jīng)更新到300,小于150的數(shù)據(jù)頁(yè)已經(jīng)被刷到磁盤上,因此數(shù)據(jù)頁(yè)A的最新數(shù)據(jù)一定在磁盤上,而數(shù)據(jù)頁(yè)B則不一定,有可能還在內(nèi)存中。
redo日志: 現(xiàn)代數(shù)據(jù)庫(kù)都需要寫redo日志,例如修改一條數(shù)據(jù),首先寫redo日志,然后再寫數(shù)據(jù)。在寫完redo日志后,就直接給客戶端返回成功。這樣雖然看過去多寫了一次盤,但是由于把對(duì)磁盤的隨機(jī)寫入(寫數(shù)據(jù))轉(zhuǎn)換成了順序的寫入(寫redo日志),性能有很大幅度的提高。當(dāng)數(shù)據(jù)庫(kù)掛了之后,通過掃描redo日志,就能找出那些沒有刷盤的數(shù)據(jù)頁(yè)(在崩潰之前可能數(shù)據(jù)頁(yè)僅僅在內(nèi)存中修改了,但是還沒來(lái)得及寫盤),保證數(shù)據(jù)不丟。
undo日志: 數(shù)據(jù)庫(kù)還提供類似撤銷的功能,當(dāng)你發(fā)現(xiàn)修改錯(cuò)一些數(shù)據(jù)時(shí),可以使用rollback指令回滾之前的操作。這個(gè)功能需要undo日志來(lái)支持。此外,現(xiàn)代的關(guān)系型數(shù)據(jù)庫(kù)為了提高并發(fā)(同一條記錄,不同線程的讀取不沖突,讀寫和寫讀不沖突,只有同時(shí)寫才沖突),都實(shí)現(xiàn)了類似MVCC的機(jī)制,在InnoDB中,這個(gè)也依賴undo日志。為了實(shí)現(xiàn)統(tǒng)一的管理,與redo日志不同,undo日志在Buffer Pool中有對(duì)應(yīng)的數(shù)據(jù)頁(yè),與普通的數(shù)據(jù)頁(yè)一起管理,依據(jù)LRU規(guī)則也會(huì)被淘汰出內(nèi)存,后續(xù)再?gòu)拇疟P讀取。與普通的數(shù)據(jù)頁(yè)一樣,對(duì)undo頁(yè)的修改,也需要先寫redo日志。
檢查點(diǎn): 英文名為checkpoint。數(shù)據(jù)庫(kù)為了提高性能,數(shù)據(jù)頁(yè)在內(nèi)存修改后并不是每次都會(huì)刷到磁盤上。checkpoint之前的數(shù)據(jù)頁(yè)保證一定落盤了,這樣之前的日志就沒有用了(由于InnoDB redolog日志循環(huán)使用,這時(shí)這部分日志就可以被覆蓋),checkpoint之后的數(shù)據(jù)頁(yè)有可能落盤,也有可能沒有落盤,所以checkpoint之后的日志在崩潰恢復(fù)的時(shí)候還是需要被使用的。InnoDB會(huì)依據(jù)臟頁(yè)的刷新情況,定期推進(jìn)checkpoint,從而減少數(shù)據(jù)庫(kù)崩潰恢復(fù)的時(shí)間。檢查點(diǎn)的信息在第一個(gè)日志文件的頭部。
崩潰恢復(fù): 用戶修改了數(shù)據(jù),并且收到了成功的消息,然而對(duì)數(shù)據(jù)庫(kù)來(lái)說,可能這個(gè)時(shí)候修改后的數(shù)據(jù)還沒有落盤,如果這時(shí)候數(shù)據(jù)庫(kù)掛了,重啟后,數(shù)據(jù)庫(kù)需要從日志中把這些修改后的數(shù)據(jù)給撈出來(lái),重新寫入磁盤,保證用戶的數(shù)據(jù)不丟。這個(gè)從日志中撈數(shù)據(jù)的過程就是崩潰恢復(fù)的主要任務(wù),也可以成為數(shù)據(jù)庫(kù)前滾。當(dāng)然,在崩潰恢復(fù)中還需要回滾沒有提交的事務(wù),提交沒有提交成功的事務(wù)。由于回滾操作需要undo日志的支持,undo日志的完整性和可靠性需要redo日志來(lái)保證,所以崩潰恢復(fù)先做redo前滾,然后做undo回滾。

我們從源碼角度仔細(xì)剖析一下數(shù)據(jù)庫(kù)崩潰恢復(fù)過程。整個(gè)過程都在引擎初始化階段完成(

延伸閱讀

學(xué)習(xí)是年輕人改變自己的最好方式-Java培訓(xùn),做最負(fù)責(zé)任的教育,學(xué)習(xí)改變命運(yùn),軟件學(xué)習(xí),再就業(yè),大學(xué)生如何就業(yè),幫大學(xué)生找到好工作,lphotoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動(dòng)軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計(jì)培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)學(xué)習(xí)是年輕人改變自己的最好方式