幾種文件系統的介紹

 

每個操作系統都有配套的文件系統,分別提供了不同的特性。本章簡單的介紹一些的文件系統,比如具有很高歷史地位的BSD FFS,傳統而流行的Linux Ext2Macintosh HFS,還有高級的Window NTFSSGI IrixXFS

從歷史角度,文件系統就是一種管理持久存儲介質的方法。大多數文件系統的基礎都是簡單的目錄和文件多級結構。這種設計雖然簡單,但是卻可以有許多實現。可能最精髓的實現就是BSD FFSBerkeley Software Distribution Fast File System)了。

 

3.1          BSD FFS

 

大部分現代文件系統的祖先都能追溯到FFS,所以對文件系統的完整介紹不可能忽略它。BSD FFS在原有Unix文件系統的基礎上改進了性能和可靠性,於是在後來的幾乎10年內都是文件系統健壯性和速度的標準。在它的框架裏,有一個超級塊,一個塊位圖,一個i-node位圖,和一些預分配的i-node數組。這種設計可在許多現代文件系統裏找到。

FFSUnix文件系統的第一個改進是塊大小。FFS使用任何大於或等於40962的冪作爲塊的字節大小。僅這一個改進就使性能提高了一倍,原因很簡單:相比搜尋和讀取多個塊,對磁盤的連續讀取能達到更高的帶寬。對磁盤的連續讀寫毫無疑問是最快的方式,即使未來也是如此。

大的塊也會有代價:磁盤空間的浪費。實際上,McKusick的報告說,在一個塊大小爲4096字節的文件系統了,總共775MB的文件會導致45.6%的額外空間浪費,即除了文件本身數據佔用的空間外,文件系統還需要353MB的空間來“管理”這些文件。FFS通過把塊分片(fragments)來克服這個問題。片(fragment)最小可以爲512字節,一般是1024字節。FFS通過塊位圖來管理片,這樣塊位圖不僅需要記錄所有塊的狀態,還要記錄所有片的狀態。分片策略允許FFS爲大文件採用較大的塊,而又不會因爲小文件浪費太多的空間。

FFS的第二個改進是減少磁盤頭的移動。顯然磁盤頭頻繁從一個地方移動到另一個地方是非常耗時的。通過仔細的安排數據在磁盤上的位置和結構,文件系統能儘量減少磁頭的尋道時間。爲此,FFS引入了柱面組(cylinder groups)的概念,深入到磁盤的物理結構(磁頭的個數,磁道(tracks),柱面(cylinders)及每個磁道上的扇區(sectors)數)來提高性能。物理上,一個柱面組就是所有磁頭對應的同一位置的磁道上的所有塊,如下圖所示:

Practical%20File%20System%20Design%20-%2001.JPG?display=thumb&width=420&height=420

 

本質上,柱面組就是磁盤的一個垂直切片。這個改進能提升性能的原因是,讀取多個塊的數據只需切換不同的磁頭。而磁頭的切換是一個電子操作,比其他物理操作(比如移動磁頭)要快得多。

FFS使用柱面組的局域性來組織磁盤上的數據。比如,很多文件系統把連續的位圖塊放在整個磁盤的開始部分,但FFS把它們分散到每個柱面組裏。i-node的位圖和預分配i-node的位圖也有類似處理。FFS還試圖把文件的數據放在i-node的附近,減少讀取文件元數據和實際內容之間的尋道時間。爲了讓數據在磁盤裏均勻散佈,FFS還把新目錄放到不同的柱面組裏。

在設計FFS的時候,採用柱面組是一個很好的方案。但是現代的磁盤隱藏了太多的物理結構,導致FFS這樣的文件系統不再有預期的作用。現代的磁盤驅動已經把FFS做的大部分事情都做過了,而且做得更好更精確,因爲磁盤驅動程序擁有磁盤的所有信息。柱面組是一個好想法,但是現在由磁盤驅動程序來管理,而不是文件系統了。

除了仔細安排文件系統元數據的寫順序,FFS還強制所有元數據寫操作要同步完成。比如刪除文件時,對應目錄的更新必須直接寫入磁盤,不通過內存緩衝。同步元數據寫操作能保證,只要寫操作返回,那麼元數據一定已經寫到了磁盤上。但是,需要寫的元數據往往只佔用單個塊,並分佈在不同的位置,於是文件系統的I/O操作速度上限就被這些單個塊的寫操作拖了後腿,因爲這種方式是最慢的磁盤寫方式。

在二十世紀80年代,FFS通過引入柱面組的概念,提供了Unix文件系統沒有的高性能和高可靠性。但現在的磁盤驅動徹底隱藏了這些細節,於是FFS不再有當初的輝煌。而FFS仔細的安排元數據的寫順序,以及強制性的同步寫,反而成爲了更大的性能瓶頸。雖然現在FFS已不再是Unix文件系統裏最快和最安全的了,但它永遠是一個標準。

 

3.2          Linux ext2

 

Linux Ext2文件系統是在傳統Unix文件系統基礎上實現的一個高效版本,它支持的唯一“非標準”特性是訪問控制列表(access control lists)。Ext2通過放鬆對系統一致性的要求,來達到極高的性能,同時使用非常複雜的文件系統檢測程序來發現和修復文件系統的損壞。

Ext2FFS非常相似,但它沒有使用柱面組的概念,而是讓驅動程序自己完成這些映射。Ext2文件系統把整個磁盤劃分成幾個固定大小的塊組(block groups),每一個塊組都像是一個微型的文件系統,擁有完整的超級塊,塊位圖,i-node位圖和i-node列表。這樣即使在大部分磁盤都損壞的情況下,文件系統檢測程序仍然可以恢復部分文件。

Ext2FFS最大的不同是,Ext2從不保證文件系統的一致性,也不保證寫操作返回後,數據一定已經在磁盤上。實際上,Ext2的所有操作都是在內存緩衝區裏完成的,除非實在需要把數據刷到磁盤上了,這使Ext2的測試性能非常引人注目。在有些測試裏,由於根本沒有向磁盤寫過任何數據,Ext2的性能完全取決於操作系統能多快的進行memcpy()

這種模型和FFS採用的強制同步寫模型形成了鮮明的對比。Ext2的哲學很明顯:在Linux世界裏,重啓是極其稀有的事情,所以使系統在99.9%的時間裏擁有高性能,比任何事情都重要。

當然,如果這種哲學是完全正確的話,所有的文件系統都會這麼做了。Ext2的模型並不是完美無暇,對於有些應用程序甚至是完全不適用的。由於Ext2不保證文件修改操作被刷寫到磁盤上的順序,所以有可能(雖然可能性有點小)後來的修改被先寫到磁盤。雖然文件系統檢測程序能保證整個Ext2系統的一致性,但是這個無序性漏洞會使應用程序疑惑,甚至因爲文件狀態的不一致而崩潰。

上面的描述聽起來可怕,實際中卻很少碰到。通常,Ext2文件系統比基於FFS的其他文件系統能快上10倍。

 

3.3          Macintosh HFS

 

HFS誕生於1984,並且和所有先前的文件系統都不同。我介紹它的原因是,它是第一個從設計上支持圖形用戶界面的文件系統,我們在它的許多數據結構的設計裏都能看到這一點。

基本上,HFS沒有哪一點像傳統文件系統。它沒有i-node列表,沒有顯而易見的目錄,並且記錄文件塊的方式也很奇怪。唯一能在HFS裏找到的相似點是,它也有一個塊位圖,記錄哪些塊空閒,哪些塊已分配。

HFS廣泛的使用B*樹來存儲文件系統結構。它有2個主要的數據結構,編目文件(catalog file)和擴展溢出文件(Extent Overflow File)。編目文件裏存儲4種對象:目錄記錄(directory records),目錄線索(directory threads),文件記錄(file records),文件線索(file threads)。

每個文件或目錄都有2個結構與之關聯:記錄(record)和線索(thread)。線索對象存儲文件的名字和所屬的目錄。記錄對象存儲文件的普通信息,比如3個時間戳,文件數據等。除此之外,文件系統還存儲了每個文件的GUI信息。當在GUI下瀏覽文件系統時,需要知道如何顯示每個文件的圖標,以及顯示的位置。在當時,直接在文件記錄裏存儲這些信息是不尋常的。

編目文件(catalog file)採用一種緊緻的結構存儲指向卷內所有文件和目錄的引用,它對文件系統的層次結構進行了編碼,不像傳統文件系統那樣直接的分開存儲每個目錄的內容。通過編目(catalog),單個目錄下的內容被線索記錄(thread records)收集(threaded)到一起。

編目文件裏,搜索的關鍵字是父目錄的ID和對象自己的名字。於是在HFS裏,每個文件和它的父目錄有很強的聯繫,因爲每個文件記錄都包含了父目錄的ID

編目文件的結構非常複雜,因爲它要記錄所有文件和目錄的信息,同時也導致整個文件系統必須順序訪問(serialization)——這對於多線程的文件I/O操作非常不理想。在HFS裏,任何創建文件、修改文件的操作都需要鎖住編目文件,別的線程即使只讀訪問它都不行。編目文件的訪問必須是單寫者/多讀者模式。

HFS爲每個文件引入了資源分支(resource fork)和數據分支(data fork)的概念,這在當時是個難得的進步,爲GUI系統提供了必需的功能抽象。把這2種數據流(streams,或者叫“分支(fork)”)概念區分開來,使得一個文件的其他信息,比如圖標、程序資源或其他元數據,可以直接存儲在文件裏。

存儲在資源或數據分支裏的文件數據可以通過擴展映射(extent maps)來訪問。HFS編目文件的每個文件記錄可以存儲3個擴展,擴展溢出文件(Extent Overflow File)存儲餘下的文件擴展,搜索的關鍵字是文件ID編碼,擴展的索引,和所在的分支。與編目文件一樣,擴展溢出文件存儲了所有文件的擴展,再次導致了文件系統只能順序訪問。這給多線程程序訪問文件系統帶來了很大的侷限。

HFS還有另一個嚴重的侷限:每個卷的塊數最多隻能是65536。主目錄塊(master directory block)只使用2字節來存儲卷內的塊個數。這個侷限使HFS不得不使用更大的塊,比如在1GB的磁盤上,HFS使用32K的塊也不少見,導致了相當的磁盤浪費。這裏的教訓很明顯:讓你設計的數據結構更持久。回想當初,主目錄塊裏包含了許多無關緊要的字段,完全可以騰出2個字節給“塊個數”字段。

HFS後來的一個版本,HFS+,去掉了原來的一些限制,比如塊的個數,但是對HFS內部結構卻改動很少。HFS發佈14年後,HFS+終於在Mac OS 8.1上開始服役了。

儘管HFS有諸多侷限,但它開闢了文件系統的一個新典範,即直接支持圖形化環境。HFS最大的侷限在於,它只支持單線程,以及所有文件和目錄的信息都存儲在一個文件裏,即編目文件(catalog file)。把所有文件的擴展信息存儲在一個文件裏(擴展溢出文件)和限制塊個數爲65536一下,也是HFS的嚴重侷限。但是,資源和數據分支的概念,提供了一種全新的存儲文件和元數據的方案。HFS爲支持GUI的文件系統設定了一個標準,但是它在其他許多關鍵的領域,比如性能和擴展性,有着很大的缺陷。

 

3.4          Irix XFS

 

Irix操作系統是SGI開發的一個Unix系統變種,並提供了一個非常成熟的文件系統,叫做XFSXFS支持日誌(journaling),64-bit文件,和高並行的操作。開發XFS的一個主要動力是支持非常大的文件系統——擁有成百上千GB的在線存儲,百萬的文件,和上GB的文件。XFS是文件系統裏的“鋼鐵巨人”。

雖然XFS支持文件系統的所有傳統抽象,但是卻在實現方式上另闢蹊徑。XFS完全沒有采用傳統文件系統的實現方式,無論是空閒磁盤空間的管理,i-node,文件數據,還是目錄內容。

大家都知道,管理磁盤空閒塊最直接的方法是使用位圖,每個bit表示一個塊。XFS卻使用一對B+樹來管理。XFS把磁盤分成許多分配組(allocation groups,與FFS的柱面組有點相似),每個分配組裏都有一對B+樹記錄組內的空閒空間,其中一個按照空閒空間的起始塊號排序,另一個按照空閒空間的長度排序。這樣文件系統就既可以根據已分配空間的位置來申請新空間,也可以根據需要的空間大小來申請新空間。顯然這種組織方式能爲給定文件找到更合適的空閒塊,唯一可能的缺點是2B+樹維護了同樣數據的不同形式。如果由於某種原因,致使它們之間的同步失效,那麼這2B+樹就會不一致,導致不可預料的後果。不過由於XFS是帶日誌的文件系統,一般情況下,不會發生這種事情。

XFS與傳統Unix文件系統不同的另一點是,它不預分配i-node節點。XFSi-node列表並不是固定大小的,而是每個分配組(allocation group)根據自己的需要臨時分配。XFS在每個分配組裏使用B+樹來存儲i-node的位置——這是一種非常少見的架構。優點很明顯:沒有浪費預分配空間,也沒有文件系統的文件數限制。但缺點也是顯然的:如果i-node節點列表是固定大小的,查找就是一個常數複雜度的操作;而XFS裏卻要查找B+樹。

XFS使用擴展映射(extent maps)來管理文件的塊。擴展映射包括一個起始塊索引和塊的個數。XFS不是使用列表簡單的列出直接、間接或雙間接的塊,而是再次使用了B+樹,並且這次的關鍵字是塊內數據在整個文件中的位置。

採用B+樹使XFS能使用變長的擴展空間(extents),而代價是實現上的複雜性。XFS能使用一個擴展映射包含2百萬個文件塊。

XFS使用B+樹存儲目錄的內容,在當時也是一個與傳統文件系統不同的地方。傳統的文件系統把目錄的內容存儲於線性結構裏,所以導致對象太多時性能嚴重下降。XFS再次使用了B+樹,把對象的名字作爲關鍵字,方便了文件的查找,即使是包含成百上千個文件的目錄也非常高效。

XFS技壓羣雄的最後一個領域是並行I/O的支持。SGI的許多高端硬件都是高並行度的,甚至有些機器的處理器有1024個之多,所以支持細粒度鎖(fine-grained locking)是必不可少的。雖然許多文件系統允許同一文件打開多次,但內部卻對i-node進行了加鎖,阻止了真正的並行訪問。XFS去掉了這個限制,允許單寫者/多讀者訪問同一文件。對於在內存緩衝區裏的文件,多個CPU可以同時複製文件數據。對於大型磁盤陣列系統,多讀者訪問使多個請求能排隊等候磁盤控制器的處理。XFS還支持多個寫者訪問同一文件,不過需要用戶使用一種特殊的訪問模式繞過文件緩衝。

XFS給傳統文件系統注入了新的血液,它沒有采用“標準方案”,而是用更復雜的實現,換取更高的性能。XFS的高性能和高複雜度總是一個引人注目的爭論話題。

 

譯自《Practical File System Design》Chapter 3。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章