XFS 文件系统 (一) :设计概览
文章目錄
- 0 前言
- 1 設計背景
- 2. 需要解決的問題
- 2.1 異常恢復太慢
- 2.2 不支持大文件系統
- 2.3 不支持大型稀疏文件
- 2.4 不支持大型連續文件
- 2.5 不支持大目錄
- 2.6 不支持過多文件個數
- 3 XFS 架構
- 4 痛點解決
- 4.1 Allocation Groups
- 4.2 Manging Free Space
- 4.3 大文件的支持
- 5 總結
0 前言
雖然工作精力主要是在 存儲引擎方向上,但是目前業界大多數的存儲引擎都是構建在 os fs上, 所以深入理解文件系統工作原理對于存儲引擎的設計也有不少的幫助。
尤其是近期工作中遇到一些 engine on ape-xfs 的性能問題,發現文件系統的知識欠缺還是比較嚴重的。
舉個例子,on aep 也就是 pmem 上做了一個fsdax 模式的pmem namespace,像使用磁盤一樣使用它 需要格式化為對應的文件系統。因為 pmem 是插在內存插槽上(和cpu 更近),且libpmem 驅動僅只支持 dax 模式的掛載,用于加速訪問pmem。所以 on pmem 的文件系統 是無法使用 page-cache 的,也就是像 inode/dentry 這樣的文件/目錄元數據 信息是沒有辦法緩存到 icache/dcache的,這樣,針對這一些元數據的更新就需要直接落在pmem上,像存儲引擎的 wal 是需要頻繁寫文件,那么文件的inode 元信息(file size)的更新就會非常頻繁(除非預分配),沒有預分配的情況下寫性能就會非常之差。
這里如果能夠深入了解文件系統的基本原理,這樣的問題抓個棧就是一眼的事情,不需要消耗過多的時間。
本篇 以及 后續的文章還是以技術設計 為主 進行學習,不會太深入代碼。
先以 xfs 設計實現為主,畢竟centos7/8 的默認文件系統,后面再逐個梳理 與其他文件系統的實現差異,畢竟文件系統過于龐大,這里僅僅做一些初步設計的記錄
1 設計背景
xfs 是大名鼎鼎的 硅谷 圖形圖像高性能計算公司巨頭 SiliconGraphic Inc 1993 年為自己內部 高性能服務器設計的文件系統。因為現在的 不少開發者 深度參與了 xfs 的設計開發,所以才成為今天centos 的主流文件系統。
XFS 被 SGI 設計出來的目的肯定是未來解決已有文件系統在大多數場景下的問題的,SGI 內部現有的文件系統 EFS(existing file system) 因為設計,無法發揮硬件性能,導致文件系統成為 os 的 i/o 瓶頸。還有很多其他功能上的限制,主要是以下幾個方面。
- EFS 采用的是 extent 方式管理 磁盤塊的分配 以及 調度磁盤IO,無法完全發揮磁盤介質性能。
- 單個文件系統的大小不能超過 8G (當時的磁盤已經有T級別的了,hdd),單個文件的大小不能超過2G。
- 在EFS 上解決一些功能上的限制和 性能問題,因為架構設計,工作量基本接近重寫了。
因為SGI 提供給用戶的服務器需要解決 用戶大量的視頻/圖像 存儲需求 以及 訪問性能,這一些隨著用戶需求的不斷增加(全球化時代 上層互聯網應用在高速發展,單服務器的存儲體量在不斷增加,存儲更大性能更快是當時的服務器存儲的必然趨勢。。。),滿足不了需求的SGI 需要開辟新疆土,所以就有了XFS。
2. 需要解決的問題
這里新設計的 XFS 需要解決的問題基本就是前面設計背景中描述的EFS的現有功能/性能問題,會對每一個問題做一個展開描述。
2.1 異常恢復太慢
EFS 是基于 BSD的 Fast File System(不太熟) 設計的,在機器異常之后啟動一個守護程序重新 從磁盤 load 文件系統的元數據,達到一個一致性狀態。這個過程會需要 fsck 不斷的檢查一個 8G 的文件系統中 上百個inode 需要花費幾分鐘的時間(HDD的帶寬應該有百M,這么慢的話大概率還是文件系統設計的問題),隨著磁盤容量得不斷增加, 當達到TB 級別以及 上萬的 inodes,如果還是這樣 recovery 速度是不能忍受的。
這里啟動 fsck check 一致性的過程應該是 檢查了全量文件,后面的XFS 設計中就只會檢查元數據了。
2.2 不支持大文件系統
這里也就是 EFS 不支持 管理大文件系統容量。SGI 希望文件系統能夠支持 PB級別的容量管理功能,但是當時業界主流的文件系統基本都是 GB 級別,像是EFS 就僅僅支持8GB。因為EFS 管理文件系統空間的數據結構是沒有辦法動態擴展的,它用 32bit的 bitmap指針管理磁盤空間,32bit 的指針最多能夠管理40億的block,即使每一個block 的大小是8K ,最多也只能管理32T 的空間。
2.3 不支持大型稀疏文件
當時的業界也沒有支持全量 64bit 的 稀疏文件存儲。稀疏文件便于壓縮,這樣的文件一般是針對大視頻處理之后形成的。
2.4 不支持大型連續文件
EFS支持 超大連續塊的存儲下讀性能不友好。EFS 使用的是 bitmap 數組結構來管理文件系統中的空間分配和釋放記錄。想要在一段超大連續空間中讀取指定的部分區域,查找性能并不會特別好。因為寫入的時候在連續的磁盤空間上寫入(順序寫)本身對HDD性能非常友好,但是讀的時候在超大文件下的查找(即使是二分) 因為bitmap 數組結構的限制 會產生多次i/o,而如果不分配連續塊,那寫性能將會巨差。
2.5 不支持大目錄
EFS 并不支持一個目錄下 上千的文件管理機制。還是性能問題,因為大多的文件系統當時從一個目錄下找一個文件是需要順序遍歷這個目錄下的文件(懷疑目錄項下的文件管理用的鏈表),還有一些使用的是hash 數據結構,這對點查性能友好,但是大范圍掃描整個目錄文件的時候性能也會很差。
當時的 NTFS 則使用 Btree 對目錄下的文件entries 進行管理。
2.6 不支持過多文件個數
當時的EFS 理論上在一個文件系統內支持超大數量的文件,但是實際過程中并非如此。因為E FS 在創建文件提供的時候就已經分配好了足量個數的 inodes,這在文件系統并沒有太多文件的情況下對磁盤空間浪費較為嚴重。同樣也為文件系統管理如此巨量 的inode 帶來負擔,尤其是寫入了很少的文件卻需要從如此巨量的inode 中查找。
總之,因為EFS 內部架構設計和各個小組件的數據結構選型,導致當前文件系統的各種功能并不完備,存在較多問題,所以 全新的文件系統 XFS 設計迫在眉睫。
3 XFS 架構
基本架構如下
這個當時 (1996)年最初的XFS 基本架構。
和其他傳統文件系統一樣,都有一個 transaction manager 以及 volumn manager。XFS 支持了標準的 UNIX 和 POSIX 的語義,在當時的 SGI 自己的內核 IRIX 中基本使用了內核所提供的有利特性,包括buffer/page cache,dcache(directory cache) 以及 icache(當時叫vnode cache)。
整個XFS 架構被模塊化為了幾部分:
- 最核心,最重要的就是 space manager。這個模塊用來管理文件系統的空間釋放和 inode的分配 以及 單個文件內部空間的分配。
- IO manager。用來管理文件系統下發的i/o請求,依賴space manager 進行請求空間的分配和釋放,并且需要持續追蹤每一個文件的空間。
- Directory manager。管理文件系統的 名字空間。
- Buffer Cache。用于緩存前面的管理數據結構,將本應該存儲在磁盤上的這一些結構緩存到內存中,加速訪問。而且 buffer cache 是 被整個os 所有進程訪問的。
- Transaction manager。用于用戶對一個文件元數據的原子更新需求。這有利于加速文件系統的crash recovery。
- Volumn manager 主要是 XFS 自己做的屏蔽不通 disk driver的組件,能夠方便對接不同的磁盤驅動,簡化文件系統的實現(不需要為每一個磁盤驅動實現對應的調度接口,當然后來linux kernel 的 generic block layer 更完備得做了這個事情,只是當時SGI 是自己的服務器,自己維護的os)。
因為XFS 全新的設計,更完備的功能和更高的性能支持,其復雜度也更高,SGI 第一版本的XFS 實現已經超過50000 行 代碼,而對應其內部的EFS 才12000 行代碼。
這里簡單匯總一下 xfs 實現過程中對b+ tree 的鐘愛:
- 追蹤磁盤空閑空間的數據結構 從之前的bitmap 變更為了b+ tree。
- 目錄項下的文件管理數據結構也從之前的線性查找數據結構變更為了 b+tree.
- B+tree 管理extent map,再由 extent map管理inodes,從而達到對整個文件系統inodes 的管理。
- B+tree 用于追蹤文件系統 inodes 的動態分配
接下來看看 XFS 實現過程中如何解決之前 EFS 的問題的。
4 痛點解決
4.1 Allocation Groups
XFS 支持全64bits 的存儲管理。內部用到的所有計數變量都是 64bits 長度(block address 以及 inode nubmer)。為了充分利用 64bits 的并行性和可伸縮性,且 避免XFS 內部所有的數據結構都擴展到64bits,這里XFS 將文件系統拆分成不同的 region,也就是 AGs,當然也會考慮磁盤訪問的局部性來利用AG 設計存儲方式(畢竟。。。HDD的隨機I/O 實在是不忍直視)。
每一個AG 管理整個文件系統的一部分容量,且不通 AG 之間可以并行操作。每一個AG 大小是 500M --> 4G 之間(現在已經支持到了16M-- 1TB 之間)。每一個AG 有自己的獨立數據存儲區域,在自己的邊界區域內,管理自己內部的空閑空間和inodes。
AG結構 的設計目的 就是前面提到的提升 64bits 的文件系統并發訪問 以及 文件系統的可伸縮性, 但是要說提升磁盤訪問的局部性 這個 很少,主要是用在目錄項的存儲中。因為文件系統創建的文件會分布在不同的AG內部,如果創建了目錄,那針對這個目錄下創建的文件 inodes 和 blocks 索引都會放在這個目錄對應的AG內部,利用 磁盤訪問的局部性 (os 預讀)加速讀性能。不同的AG 內部可以通過 文件系統全局的 ag 指針/files/directories 來訪問整個文件系統其他 AG 的文件。
當然AG 設計最主要的目的是為了 提升64bits 下的并發訪問性能 和 空閑空間管理以及 inodes 分配的性能。因為 SGI 的EFS 都是單線程處理 block 的分配和釋放。這種方式隨著文件系統的規模不斷增加,可能成為性能瓶頸,通過設計 AG 內部 擁有獨立的數據結構,這樣XFS 文件系統可以 在不同AG 互不影響的情況下 并發調度 一些 釋放/分配 磁盤空間的操作。
更詳細的AG 設計后面的系列文章會展開。
4.2 Manging Free Space
空間分配/釋放的性能 和 可擴展性 是衡量一個好的文件系統的基礎。能夠高效的分配和釋放空間,并且能夠很好得處理空間碎片問題 對文件系統的性能至關重要。
XFS 在空間管理的數據結構上 相比于 EFS 來說做了比較大的改動,在每個AG 內部 將EFS原本的 bitmap 換成了b+tree。其中空閑空間的 start block的維護有一個單獨的b+ tree,同時 length(有多少個空閑塊)的維護也有一個b+tree,這樣想要查找 一個空閑塊的時候可以根據傳入的空閑塊的個數以及 起始空閑塊進行,極大得提升了空閑空間的索引效率。
4.3 大文件的支持
在64bits 下支持超大的稀疏文件,也就是允許大文件內部有空洞,而這一些空洞不應該占用磁盤空間。如果按照傳統的磁盤block 方式來管理一個文件所占用空間的話,那在這種場景下需要管理大量的blocks。XFS 采用了Data extent 的方式,每一個 extent 都是一段連續的分配給當前文件的block 空間,由一個個block offset組成,這樣對于超大文件的空間管理就更加高效了。原本 采用block 的方式 , 可能一個文件需要 百萬級別的block,現在這一些block 都可以聚合成一個大的extent統一管理,在extent 內部會盡可能保持 block 的連續性,甚至隨著文件大小的不斷增加,不同的extent 之間也可以合并。
每一個 Data Extent 是128bits,其中1bits 用來記錄標識,高54bits 存儲block 的偏移地址,后52bits 存儲 完整的 block number,后21 bits 存儲block 個數 (一個extent中能夠保存 200w的block,也就是8G 的磁盤空間)。
5 總結
還有更多 XFS 如何解決 EFS 前面提到的痛點方案,因為 整體的體系較為龐大,這里先做一個記錄,更多的細節會慢慢展開。
總結
以上是生活随笔為你收集整理的XFS 文件系统 (一) :设计概览的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 有谁知道周星驰抢劫处女贞操的那个片段出自
- 下一篇: 通过 RDTSC 指令从 CPU 寄存器