Linux 日誌文件系統原來是這樣工做的

文件系統要解決的一個關鍵問題是怎樣防止掉電或系統崩潰形成數據損壞,在此類意外事件中,致使文件系統損壞的根本緣由在於寫文件不是原子操做,由於寫文件涉及的不單單是用戶數據,還涉及元數據(metadata)包括 Superblock、inode bitmap、inode、data block bitmap等,因此寫操做沒法一步完成,若是其中任何一個步驟被打斷,就會形成數據的不一致或損壞。node

舉一個簡化的例子,咱們對一個文件進行寫操做,要涉及如下步驟:linux

  1. 從data block bitmap中分配一個數據塊;
  2. 在inode中添加指向數據塊的指針;
  3. 把用戶數據寫入數據塊。
  • 若是步驟2完成了,3未完成,結果是數據損壞,由於該文件認爲數據塊是本身的,但裏面的數據實際上是垃圾;
  • 若是步驟2完成了,1未完成,結果是元數據不一致,由於該文件已經把數據塊據爲己有,然而文件系統卻還認爲該數據塊未分配、隨後又可能會把該數據塊分配給別的文件、形成數據覆蓋;
  • 若是步驟1完成了、2未完成,結果就是文件系統分配了一個數據塊,可是沒有任何文件用到這個數據塊,形成空間浪費;
  • 若是步驟3完成了,2未完成,結果就是用戶數據寫入了硬盤數據塊中,但白寫了,由於文件不知道這個數據塊是本身的。

日誌文件系統(Journal File System)就是爲解決上述問題而誕生的。app

它的原理是在進行寫操做以前,把即將進行的各個步驟(稱爲transaction)事先記錄下來,保存在文件系統上單獨開闢的一塊空間上,這就是所謂的日誌(journal),也被稱爲write-ahead logging,日誌保存成功以後才進行真正的寫操做、把文件系統的元數據和用戶數據寫進硬盤(稱爲checkpoint),這樣萬一寫操做的過程當中掉電,下次掛載文件系統以前把保存好的日誌從新執行一遍就好了(術語叫作replay),避免了前述的數據損壞場景。spa

有人問若是保存日誌的過程當中掉電怎麼辦?最初始的想法是把一條日誌的數據一次性寫入硬盤,至關於一個原子操做,然而這並不可行,由於硬盤一般以512字節爲單位進行操做,日誌數據一超過512字節就不可能一次性寫入了。因此其實是這麼作的:給每一條日誌設置一個結束符,只有在日誌寫入成功以後才寫結束符,若是一條日誌沒有對應的結束符就會被視爲無效日誌,直接丟棄,這樣就保證了日誌裏的數據是完整的。指針

一條日誌在它對應的寫操做完成以後就沒用了,佔用的硬盤空間就能夠釋放。保存日誌的硬盤空間大小是有限的,被循環使用,因此日誌也被稱爲circular log。日誌

至此能夠總結一下日誌文件系統的工做步驟了:blog

  1. Journal write : 把transaction寫入日誌中;
  2. Journal commit : 在一條日誌保存好以後,寫入結束符;
  3. Checkpoint : 進行真正的寫操做,把元數據(metadata)和用戶數據(user data)寫入文件系統;
  4. Free : 回收日誌佔用的硬盤空間。

以上方式把用戶數據(user data)也記錄在日誌中,稱爲Data Journaling,Linux EXT3文件系統就支持這種方式,這種方式存在效率問題:事件

就是每個寫操做涉及的元數據(metadata)和用戶數據(user data)實際上都要在硬盤上寫兩次,一次寫在日誌裏,一次寫在文件系統上。元數據倒也罷了,用戶數據一般比較大,拷貝幾個GB的電影文件也要乘以2實在是下降了效率。

一個更高效的方式是Metadata Journaling,不把用戶數據(user data)記錄在日誌中,它防止數據損壞的方法是先寫入用戶數據(user data)、再寫日誌,即在上述」Journal write」以前先寫用戶數據,這樣就保證了只要日誌是有效的,那麼它對應的用戶數據也是有效的,一旦發生掉電故障,最壞的結果也就是最後一條日誌沒記完,那麼對應的用戶數據也會丟,效果與Data Journaling丟棄日誌同樣,重要的是文件系統的一致性和完整性是有保證的。ci

Metadata Journaling又叫Ordered Journaling,大多數文件系統都採用這種方式。像Linux EXT3文件系統也是能夠選擇Data Journaling仍是Ordered Journaling的。rem

參考資料:Crash Consistency: FSCK and Journaling

來源:http://linuxperf.com/?p=153

image

相關文章
相關標籤/搜索