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

上圖詳細顯示了InnoDB存儲引擎的體系架構,從圖中可見,InnoDB存儲引擎由內存池,後台線程和磁碟文件三大部分組成。接下來我們就來簡單了解一下磁碟文件相關的概念和原理。

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

系統表空間和用戶表空間

InnoDB系統表空間包含InnoDB數據字典(元數據以及相關對象)並且doublewrite buffer,change buffer,undo logs的存儲區域。系統表空間也默認包含任何用戶在系統表空間創建的表數據和索引數據。系統表空間是一個共享的表空間因為它是被多個表共享的

系統表空間是由一個或者多個數據文件組成。默認情況下,1個初始大小為10MB,名為ibdata1的系統數據文件在MySQL的data目錄下被創建。用戶可以使用innodbdatafile_path對數據文件的大小和數量進行配置。

innodbdatafile_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)。

設置innodbdatafilepath參數之後,所以基於InnoDB存儲引擎的表的數據都會記錄到該系統表空間中,如果設置了參數innodbfilepertable,則用戶可以將每個基於InnoDB存儲引擎的表產生一個獨立的用戶表空間。用戶表空間的命名規則為:表名.ibd。

通過這種方式,用戶不用將所有數據都存放於默認的系統表空間中,但是用戶表空只存儲該表的數據、索引和插入緩衝BITMAP等信息,其餘信息還是存放在默認的表空間中。

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

重做日誌文件和歸檔文件

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

每個InnoDB存儲引擎至少有1個重做日誌文件組(group),每個文件組下至少有2個重做日誌文件,如默認的iblogfile0和iblogfile1。

為了得到更高的可靠性,用戶可以設置多個鏡像日誌組,將不同的文件組放在不同的磁碟上,以此來提高重做日誌的高可用性。

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

用戶可以使用innodblogfile_size來設置重做日誌文件的大小,這對InnoDB存儲引擎的性能有著非常大的影響。

如果重做日誌文件設置的太大,數據丟失時,恢復時可能需要很長的時間;另一方面,如果設置的太小,重做日誌文件太小會導致依據checkpoint的檢查需要頻繁刷新臟頁到磁碟中,導致性能的抖動。

重做日誌相關和Checkpoint的機制可以閱讀我之前文章的相應章節。

MySQL探秘(三):InnoDB的內存結構和特性?

mp.weixin.qq.com
圖標

重做日誌的落盤機制

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的innodbflushlogattrx_commit屬性可以控制每次事務提交時InnoDB的行為。當屬性值為0時,事務提交時,不會對重做日誌進行寫入操作,而是等待主線程按時寫入;當屬性值為1時,事務提交時,會將重做日誌寫入文件系統緩存,並且調用文件系統的fsync,將文件系統緩衝中的數據真正寫入磁碟存儲,確保不會出現數據丟失;當屬性值為2時,事務提交時,也會將日誌文件寫入文件系統緩存,但是不會調用fsync,而是讓文件系統自己去判斷何時將緩存寫入磁碟。日誌的刷盤機制如下圖所示。

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

後記

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

個人博客:

Carpediem?

remcarpediem.net
圖標

推薦閱讀:
相关文章