天天看點

THE NOVA FILESYSTEM

The NOVA filesystem

原文以及插圖均來自lwn,連結在此。

https://lwn.net/Articles/729812/

NOVA檔案系統

非易失性記憶體(NVM)是一種保證在掉電不丢資料的同時能夠快速按照位元組尋址通路的存儲。為了利用好這種新型存儲,我們需要某種樹形結構來存儲和通路資料。一般情況下我們都會想到用檔案系統,理由麼,很簡單,因為它天生就是幹這個的。不過悲劇的是傳統檔案系統如ext4,xfs這些其實并不能完美的比對這些非易失性記憶體,是以很自然的就有人想針對這玩意設計一種新的檔案系統出來,而NOVA則是其中一個不錯的嘗試。

在介紹NOVA之前,讓我們先來看看通用檔案系統在設計時一系列特定的假設。存儲的通路速度一般很慢,是以我們要盡量通過消耗一定的CPU和記憶體來減少對底層裝置的通路;一般的硬碟在随機操作時性能很差,是以我們要盡量讓資料布局比較連續;針對扇區做IO是原子操作,要麼整個扇區被寫入,要麼保持不變。所有這些假定對大多數檔案系統的設計都有很深的影響。不過很抱歉這些對非易失性記憶體裝置來說基本都是錯的。是以盡管諸如XFS或ext4之類的檔案系統可以在這種裝置上得到明顯的加速,但從頭開始針對非易失性記憶體設計一個新的檔案系統貌似更加明智一些。 于是乎,NOVA出現了,它的革命很徹底,因為它已經不是一個正常的塊裝置,而且根本無法使用核心的塊層。它直接将存儲映射到核心的位址空間,這樣既節省了塊層帶來的開銷,又降低了CPU的開銷。當然避開塊層的另一個效果是放棄掉目前很多塊層的功能,比如請求合并,隊列管理,請求優先級等等,下面讓我們仔細分析看看。

NOVA檔案系統結構

像大多數檔案系統一樣,NOVA以一個超級塊開始(這一點上還是類似的,善哉善哉),它描述了檔案系統的頂層資料結構同時也提供了其他資料結構的位置資訊。以inode為例(inode是檔案系統中檔案或目錄的内部表現形式,大家都懂得哈),NOVA的inode表被設定為以PER CPU來組織的數組,這樣任何CPU在配置設定新的inode的時候就不再需要對其他CPU上鎖。

NVM的可用空間同樣被打散到不同的CPU中,每個CPU都用了一棵紅黑樹進行管理,這樣可以加速空閑區域的合并。與inode表不同的是空閑清單維護在普通RAM而不是非易失性記憶體中。它們在檔案系統解除安裝(umount)的時候被寫回NVM,如果檔案系統未能正确解除安裝,那麼空閑清單将隻能通過掃描整個檔案系統進行重建。

下面我們來看看NOVA最有趣的地方,也就是inode的存儲方式。在像ext4這樣的檔案系統上,磁盤inode是包含許多檔案中繼資料的明确定義的結構。而為了達到更快的性能,NOVA則采取了基于日志的做法,結果是inode表中的一個inode隻是一對指向資料結構的指針,看起來像是這樣的。

THE NOVA FILESYSTEM

每個有意義的inode中繼資料包含對該檔案所做修改的日志,而inode結構中的所有資訊就是一對指針,分别訓示第一個和最後一個有效的日志條目。這些條目在非易失性記憶體中以至少4KB的chunk存在,以連結清單形式組織起來。每個日志條目訓示一個事件,比如:

*檔案屬性被修改 —— 例如,權限位修改。


*目錄中添加一個條目(顯然是針對目錄inode)。

*檔案的連結被添加。

*資料被寫回到檔案中。

下面重點講講寫資料的場景。如果一個程序寫入了一個空檔案,NOVA從每CPU空閑清單中配置設定所需的記憶體,拷貝資料到該空間。然後将追加一個條目到inode日志中訓示檔案新長度,同時指向數組中資料寫入的位置。最後,inode尾部指針原子更新并使得這個操作全局可見。That's it! 再來看看覆寫寫的場景,事情将會有些不同。由于NOVA是寫時複制檔案系統,是以第一步是再次為新資料配置設定新的非易失性記憶體。如果需要,資料會從舊頁拷貝到新頁,然後添加新的資料。最後指向新頁的條目将被添加日志中,尾部指針被更新,并且這些頁的舊日志條目被無效。到這裡操作就完成了,舊的資料頁以後可以被釋放以重新使用。

是以,NOVA中的磁盤inode其實并不是真正意義上對一個檔案的中繼資料的描述,而可以認為是一組對inode的操作集合,當我們按照順序(跳過無效的)執行這些操作将産生檔案中繼資料的一個完整描述。使用這種存儲方式的優點在是當檔案修改時隻需最小的鎖就可以達到最快的更新,同時顯而易見通路檔案時我們的速度會慢一些。針對這個慢的問題,NOVA通過在檔案打開時在記憶體中生成并儲存一份檔案中繼資料來緩解,這個動作其實也不慢,因為整個操作都是可以由CPU直接尋址來操作,這也算是NVM的一個特點吧。是以如果我們将這類結構存儲在旋轉磁盤上,或者普通塊的SSD上,都将會是災難。

這樣的日志結構同時還具備另外一個有趣的特性,那就是日志中的每個條目都包含了建立條目時設定的“紀元編号”(epoch number)。這樣我們建立快照将非常簡單,我們隻需要增加全局紀元編号并将先前的編号與指向快照的指針關聯起來就可以了。當快照挂載時,可簡單忽略掉紀元編号大于快照編号的任何日志條目,這樣就可以獲得打快照時檔案存在的視圖。當然這裡還有一些細節需要打磨,不過這仍然是該問題一個非常優雅的解決方案。

DAX及其他

讀者可能很想知道NOVA如何與核心的DAX接口互動,該接口允許應用程式将非易失性記憶體中的檔案直接映射到它們的位址空間中,進而在将來的通路時完全繞過核心。從上面的分析我們可以看出,對于一個COW檔案系統我們很難利用DAX。在2016年介紹NOVA的論文

http://cseweb.ucsd.edu/~swanson/papers/FAST2016NOVA.pdf

作者也說他們沒有嘗試過DAX,而是支援一種被稱為“原子mmap”的替代機制,其将資料拷貝到“副本頁面”并反過來映射它們。某種意義上,原子mmap部分實作了頁面緩存的功能。

能直接通路非易失性記憶體一直是NVM最引入矚目的特性之一,是以沒有DAX大家會很失望的。貌似作者也懂的,是以這次送出給社群的更新檔已經聲稱支援DAX了。從這次送出的文檔和代碼來看,NOVA通過對已經映射到程序位址空間的檔案部分禁用COW來實作這個功能,這樣對檔案的修改就可以在原地展開了。當然這樣做的一個重要的缺陷是對于這些已經映射到程序位址空間的檔案頁将無法通過write()寫入(原因前面說過啦,因為write需要用到COW這個機制啦)。解決這個問題可能需要一些比較複雜的邏輯,在另一篇論文中有詳細的描述

http://cseweb.ucsd.edu/~swanson/papers/TechReport2017HardenedNOVA.pdf

NOVA内置了一些自我保護措施,比如資料和中繼資料的checksuming,然而似乎這個特性引起了不小的争議。當你把整個存儲陣列映射到核心位址空間後寫入一個雜亂的指針就有可能直接破壞持久化的資料。這在bug-free的核心将不是一個問題,但顯然現實是殘酷的。。。為了防止無意的資料覆寫,NOVA可将整個陣列映射為隻讀。當必須進行修改時,處理器的寫保護位将暫時清除,允許核心繞過記憶體權限來操作。禁止寫保護這個動作在過去一直被認為非常危險,現在也依然不受歡迎。是以看起來NOVA要想想别的辦法了。

在NOVA被認真考慮合并到上遊前,還有其他一些事情需要解決。例如,它僅适用x86-64架構,且由于使用了PER CPU的inode表結構,當兩台機器的CPU數量不同時将無法将NOVA檔案系統從一個系統移動到另外一個。另外NOVA還不支援ACL或者磁盤配額,也沒有檔案系統的檢查工具等等。開發者已經知道了這些問題并且後面會處理它們。

檔案系統開發者注意到這些細節并且努力使他的檔案系統合并至核心的行為是令人鼓舞的,尤其當這個情況發生在學術界的時候(确切的說是加州大學聖地亞哥分校)。因為一般情況下學術工作在論文出版和捐贈資金用完後就會停下來,是以通常情況下自由軟體從大學擷取的源碼遠遠低于人們的期望。但願NOVA可以引領一個新的潮流。

寫到這裡就差不多了,這個檔案系統的很多其他方面還請參閱上面提到兩篇論文以及更新檔自身的文檔。NOVA将會是一個值得關注的項目。如果進展順利它将讓我們能夠從巨大、快速的非易失性記憶體陣列中獲得卓越的性能,希望這一天快點到來。