MySQL探祕(四):InnoDB的磁碟檔案及落盤機制

程式設計師歷小冰發表於2018-09-09

 任何一個技術都有其底層的關鍵基礎技術,這些關鍵技術很有可能也是其他技術的關鍵技術,學習這些底層技術,就可以一通百通,讓你很快的掌握其他技術。如何在磁碟上儲存資料,如何使用日誌檔案保證資料不丟失以及如何落盤,不僅是MySQL等資料庫的關鍵技術,也是MQ訊息佇列或者其他中介軟體的關鍵技術之一。

InnoDB整體架構
 上圖詳細顯示了InnoDB儲存引擎的體系架構,從圖中可見,InnoDB儲存引擎由記憶體池,後臺執行緒和磁碟檔案三大部分組成。接下來我們就來簡單瞭解一下磁碟檔案相關的概念和原理。

 InnoDB的主要的磁碟檔案主要分為三大塊:一是系統表空間,二是使用者表空間,三是redo日誌檔案和歸檔檔案。二進位制檔案(binlog)等檔案是MySQL Server層維護的檔案,所以未列入InnoDB的磁碟檔案中。

系統表空間和使用者表空間

 InnoDB系統表空間包含InnoDB資料字典(後設資料以及相關物件)並且doublewrite buffer,change buffer,undo logs的儲存區域。系統表空間也預設包含任何使用者在系統表空間建立的表資料和索引資料。系統表空間是一個共享的表空間因為它是被多個表共享的

 系統表空間是由一個或者多個資料檔案組成。預設情況下,1個初始大小為10MB,名為ibdata1的系統資料檔案在MySQL的data目錄下被建立。使用者可以使用innodb_data_file_path對資料檔案的大小和數量進行配置。

 innodb_data_file_path的格式如下:

innodb_data_file_path=datafile1[,datafile2]...
複製程式碼

 使用者可以通過多個檔案組成一個表空間,同時制定檔案的屬性:

innodb_data_file_path = /db/ibdata1:1000M;/dr2/db/ibdata2:1000M:autoextend
複製程式碼

 這裡講/db/ibdata1和/dr2/db/ibdata2兩個檔案組成系統表空間。如果這兩個檔案位於不同的磁碟上,磁碟的負載可能被平均,因此可以提高資料庫的整體效能。兩個檔案的檔名之後都跟了屬性,表示檔案ibdata1的大小為1000MB,檔案ibdata2的大小為1000MB,而且用完空間之後可以自動增長(autoextend)。

 設定innodb_data_file_path引數之後,所以基於InnoDB儲存引擎的表的資料都會記錄到該系統表空間中,如果設定了引數innodb_file_per_table,則使用者可以將每個基於InnoDB儲存引擎的表產生一個獨立的使用者表空間。使用者表空間的命名規則為:表名.ibd。  通過這種方式,使用者不用將所有資料都存放於預設的系統表空間中,但是使用者表空只儲存該表的資料、索引和插入緩衝BITMAP等資訊,其餘資訊還是存放在預設的表空間中。

InnoDB表儲存引擎檔案

 上圖顯示InnoDB儲存引擎對於檔案的儲存方式,其中frm檔案是表結構定義檔案,記錄每個表的表結構定義。

重做日誌檔案和歸檔檔案

 預設情況下,在InnoDB儲存引擎的資料目錄下會有兩個名為ib_logfile0和ib_logfile1的檔案,這就是InnoDB的重做日誌檔案(redo log fiel),它記錄了對於InnoDB儲存引擎的事務日誌。  當InnoDB的資料儲存檔案發生錯誤時,重做日誌檔案就能派上用場。InnoDB儲存引擎可以使用重做日誌檔案將資料恢復為正確狀態,以此來保證資料的正確性和完整性。

 每個InnoDB儲存引擎至少有1個重做日誌檔案組(group),每個檔案組下至少有2個重做日誌檔案,如預設的ib_logfile0和ib_logfile1。  為了得到更高的可靠性,使用者可以設定多個映象日誌組,將不同的檔案組放在不同的磁碟上,以此來提高重做日誌的高可用性。

 在日誌組中每個重做日誌檔案的大小一致,並以迴圈寫入的方式執行。InnoDB儲存引擎先寫入重做日誌檔案1,當檔案被寫滿時,會切換到重做日誌檔案2,再當重做日誌檔案2也被寫滿時,再切換到重做日誌檔案1。

 使用者可以使用innodb_log_file_size來設定重做日誌檔案的大小,這對InnoDB儲存引擎的效能有著非常大的影響。

 如果重做日誌檔案設定的太大,資料丟失時,恢復時可能需要很長的時間;另一方面,如果設定的太小,重做日誌檔案太小會導致依據checkpoint的檢查需要頻繁重新整理髒頁到磁碟中,導致效能的抖動。  重做日誌相關和Checkpoint的機制可以閱讀我之前文章的相應章節。MySQL探祕(三):InnoDB的記憶體結構和特性

重做日誌的落盤機制

 InnoDB對於資料檔案和日誌檔案的刷盤遵守WAL(Write ahead redo log) 和Force-log-at-commit兩種規則,二者保證了事務的永續性。WAL要求資料的變更寫入到磁碟前,首先必須將記憶體中的日誌寫入到磁碟;Force-log-at-commit要求當一個事務提交時,所有產生的日誌都必須重新整理到磁碟上,如果日誌重新整理成功後,緩衝池中的資料重新整理到磁碟前資料庫發生了當機,那麼重啟時,資料庫可以從日誌中恢復資料。

寫入機制

 如上圖所示,InnoDB在緩衝池中變更資料時,會首先將相關變更寫入重做日誌緩衝中,然後再按時或者當事務提交時寫入磁碟,這符合Force-log-at-commit原則;當重做日誌寫入磁碟後,緩衝池中的變更資料才會依據checkpoint機制擇時寫入到磁碟中,這符合WAL原則。  在checkpoint擇時機制中,就有重做日誌檔案寫滿的判斷,所以,如前文所述,如果重做日誌檔案太小,經常被寫滿,就會頻繁導致checkpoint將更改的資料寫入磁碟,導致效能抖動。

 作業系統的檔案系統是帶有快取的,當InnoDB向磁碟寫入資料時,有可能只是寫入到了檔案系統的快取中,沒有真正的“落袋為安”。  InnoDB的innodb_flush_log_at_trx_commit屬性可以控制每次事務提交時InnoDB的行為。當屬性值為0時,事務提交時,不會對重做日誌進行寫入操作,而是等待主執行緒按時寫入;當屬性值為1時,事務提交時,會將重做日誌寫入檔案系統快取,並且呼叫檔案系統的fsync,將檔案系統緩衝中的資料真正寫入磁碟儲存,確保不會出現資料丟失;當屬性值為2時,事務提交時,也會將日誌檔案寫入檔案系統快取,但是不會呼叫fsync,而是讓檔案系統自己去判斷何時將快取寫入磁碟。日誌的刷盤機制如下圖所示。

log刷盤機制

 innodb_flush_log_at_commit是InnoDB效能調優的一個基礎引數,涉及InnoDB的寫入效率和資料安全。當引數值為0時,寫入效率最高,但是資料安全最低;引數值為1時,寫入效率最低,但是資料安全最高;引數值為2時,二者都是中等水平。一般建議將該屬性值設定為1,以獲得較高的資料安全性,而且也只有設定為1,才能保證事務的永續性。

後記

 我們後續還會學習binlog檔案以及資料檔案的落盤機制,還有InnoDB事務相關的其他知識,請大家持續關注。

MySQL探祕(四):InnoDB的磁碟檔案及落盤機制

相關文章