Log-structured File Systems


換到博客園排版有問題,原版在這里:http://xubenbenhit.github.io/LogStructureFileSystem.html

Log-structured File Systems

2014-12-26  #system

先來扯淡,這篇博客講的是LFS,之前寫的硬盤與磁盤冗余陣列其實是第一篇,而這個應該算是第三篇,這中間差了一篇介紹文件系統的博客,原本打算今天回去之后一起寫了,但是考慮到自己回家之后的效率不敢保證。故而先在實驗室寫完這個文章,而文件系統的資料全部在家。

1. 什么是LFS?

  首先回顧一下我們是怎么來寫Log文件的,不就是把最新的狀態一行一行的寫在日志文件的最末尾么(這個聯系是我自己YY的)。那么Log-structured File System也是一樣,就是更新數據的時候直接將數據放在末尾。如下圖: 
  

一開始,我們寫入磁盤數據塊Foo,然后旁邊的A是它的inode:


  然后,我們再寫入塊Bar,旁邊的A'是inode:

 
  最后,我們更新數據塊Foo,獲得Foo',這時候我們將其寫回磁盤,就變成這樣子:

2. LFS是怎么來的?

  LFS是在上個世紀九十年代前后搞出來的,當時的主要考慮有這個幾點(道聽途說):

  • 內存越來越大,進而可以不斷擴充Cache的容量,也就會意味着數據讀取操作可以越來越不需要訪問磁盤了,進而使得磁盤寫操作越來也成為性能瓶頸;

  • 序列磁盤數據讀取速度跟隨機讀取磁盤數據速度的差距越來越大,這種情況下如果可以將隨機磁盤操作轉換為序列磁盤操作,則收益可觀;

  • 處理小文件的時候,之前的文件系統效率不高,而事實上小文件才是常見的;此外對於小文件的寫操作,磁盤本身也不擅長,因為RAID4/RAID5處理小文件的時候性能也是不高的;

  因為有了這些,所以就有了LFSLFS首先將磁盤數據的更新緩存在Cache中,當緩存到一定規模(稱之為一個segment)的時候再一次性寫入空閑磁盤,由此獲得高性能。   當然了,說起來很簡單,做起來就不是嘍,這里面主要有兩個方面的問題:其一是整個操作過程中的文件定位;其二是磁盤空間管理。 
  這里我覺得就不按照論文的思路來寫了,因為沒勁,不如就按照自己的理解一步步來做推演吧,比較論文作者也是自己一步步想出來的。

3. 開始推演

  LFS是先在內存在存儲文件更新,這個存儲單元稱之為一個segment,等到segment存滿了的時候再一次性寫入空閑磁盤。於是乎就需要首先保證整個操作的正確和高效。

  • 首先,根據FFS(Fast FIle System)的設計經驗,需要用一個inode來存儲這個segment中每個文件的元信息,也就是文件的一些屬性,諸如大小、文件塊(文件可能需要多個磁盤block來存儲)的物理地址、權限等等。當然了,inode也是在segment中的,為了方便考慮就存儲在對應文件的后面,見第一部分的圖。注意一點,這個inode一般很小,只有128Byte左右。

  • 按照FFS的設計,將inode存儲在一塊連續的磁盤空間(物理地址是可以事先計算的),但是一次性將segment寫入磁盤這個操作本身就會使得文件的inode“散布在”整個磁盤空間,而且按照LFS的設計,文件是不可能被原地修改的,這也就意味着最新版的文件的inode的地址始終在變化!!故而按照“慣例”,設計一層間接連接(indirection),稱為imap,用來存儲各個inode的物理地址。

  • 既然有了imap,那么問題來了,imap存儲在哪兒?第一種選擇是將其存儲在磁盤的某一固定位置,但是我們注意到每次寫segment的時候都會對imap進行更新,而每次更新imap都需要將磁頭轉到固定位置,有點影響效率啊!不如將imap放在inode后面吧。 
     
    這里多說一句,imap本身可能也占用多個磁盤block,故而只需要將更新的那一塊imap放在inode后面就可以了。這樣又有個問題,imap地址不確定,怎么尋址呢?所以還是需要一個地址確定的區域,里面存儲imap的地址就可以了,這個區域稱之為CheckRegion,這里面存儲了imap各個block的物理地址。就可以通過CheckRegion->imap->inode->file的方式定位到文件了。 

  • 但是,文件夾怎么處理? 
    按照FFS的設計,所謂的文件夾無非就是一些文件名和文件inode的映射,在FFS中文件夾被當做普通的文件數據來存儲,那么LFS也這么干。於是我們就可以看到 /dir/foo 是這樣存儲的: 
     
    具體而言是這樣,首先定位到dir文件夾的inode所在的imap,然后根據查找到dir文件夾的inode物理地址,然后找到dir文件夾的物理地址,進而獲取foo文件的inode,然后在CR->imap->inode->foo。注意到這樣設計還有一個意外的好處,就是說文件夾下的文件更新操作是不需要更新文件夾本身的,這也就避免了“遞歸更新”文件夾的文件夾的文件夾。。。

    好的,至此,文件定位以及沒有問題了。但是每次這樣將segment寫入空閑磁盤,一直這樣下去,哪有那么多磁盤呢?這就涉及到磁盤空間回收(segment cleaning)的問題了。 
    一般來說,磁盤空間回收大致需要這三步:首先將一些segment讀入內存;然后判斷segment里面的block數據是否是“存活的”,也就是說文件是否處於最新版本;最后將所有的“存活”文件集中寫進segment中,而將剩下的空間回收。

  • 如何判斷block是否為最新版本? 
    為了實現這個功能,那么就需要知道segment中block的原信息了,比如它所歸屬的文件inode以及在文件中的位置。這些信息需要存儲在segment中的一個稱為segment summary block的區域中。那么我們就可以查找這個block數據的當前物理地址,比對一下就知道是否是最新版了。當然了,這樣一來,最好將imap整個加載到內存中方便查詢。 
    當然了,可以改進這個設定,為每個文件設置版本號,每次文件更新版本號遞增,將這個版本號存儲在segment summary block以及imap中,這樣只需要比對一下文件版本號就可以判斷整個文件是否是最新版本了。

  • 關於segment clean,什么時候執行呢?執行clean達到什么目標就停止呢?怎么選擇segment執行clean?以及是否需要重組live file以便獲得更好的locality? 第一個第二個實驗表明不太重要,實際操作而言,設置兩個閾值,點那個空閑segment數目低於某一閾值后執行clean,當回收使得空閑segment數目高於另一閾值后停止clean。 
    第三個問題很有講究,事實上,論文中采用的算法是計算每個segment的clean性價比(cost-benefit),這個計算公式具體參考論文吧。為此在CheckRegine中保存一個segment usuage的表單。 
    第四個問題,也是很有技巧性的地方,論文中的做法是按照存活文件最近一次更改時間的順序依次寫入segment中。

      至此,描述的差不多了,下面看看兩個細節。

  • Check Point Check Region中包含的數據imap地址以及segment usage等等都是在變化的,所以需要每過一段時間更新一下。正常情況下先將Cache中的segment寫入磁盤,然后更新Check Region,因為考慮到更新CR過程中也可能出現異常,所以用兩個timestamp塊包裹住真實的CR數據,只有當前后兩個timestamp一致的時候才認為這個CR是正常的。為了避免在更新CR過程中出現故障導致CR不可用,LFS使用兩個CR,交替使用,這樣即使故障了,也可以用另一個CR來恢復。

  • Crash Recovery 遇到特殊故障,LFS怎么恢復呢? 首先,尋找到最新的可用CR,這里的“可用”表示該CR的前后timestamp是一致的。然后使用論文中提及的Roll-Followed算法來恢復。這里面有一個“奇怪”的地方,就是說imap的最新版block不都已經在segment里面了么,那么直接用這個更新就可以了嘛!!其實不是的,因為考慮到磁盤寫操作的時候imap本身可能沒有寫正確。。。。

    至此,應該是差不多了,詳細的東系統的介紹直接看下面的資料吧。


4. 參考文獻

  1. http://pages.cs.wisc.edu/~remzi/OSTEP/file-lfs.pdf
  2. http://www.eecs.berkeley.edu/Pubs/TechRpts/1992/CSD-92-696.pdf
  3. http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.54.502
  4. http://blog.notdot.net/2009/12/Damn-Cool-Algorithms-Log-structured-storage

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM