Linux 與文件系統具有有趣的關係。因為 Linux 是開放式的,所以它往往是下一代文件系統和創新文件系統理念的關鍵開發平台。兩個有趣的最新示例包括可大規模擴展的 Ceph 和連續快照文件系統 nilfs2(當然,主力文件系統,比如第四個擴展文件系統 [ext4] 的演化)。它還是舊有文件系統的考古遺址 — DOS VFAT、Macintosh(HPFS)、VMS ODS-2 和 Plan-9 的遠程文件系統協議。但是對於您發現在 Linux 內受支持的所有文件系統,有一個因其實現的功能會讓人產生相當大的興趣:Oracle 的 Zettabyte 文件系統(Zettabyte File System,ZFS)。
ZFS 是由 Sun Microsystems(在 Jeff Bonwick 下)設計和開發的,在 2004 年首次公布,並在 2005 年融入 Sun Solaris)。雖然將最流行的開放式操作系統與談論最多的、功能最豐富的文件系統配對在一起是最理想的匹配,但是許可問題制約了集成。Linux 通過 GNU 公共許可證(General Public License,GPL)獲得保護,而 ZFS 是由 Sun 的通用開發和發布許可(Common Development and Distribution License,CDDL)涵蓋的。這些許可協議具有不同的目標並引入了衝突的限制。所幸,這並不意味著您作為 Linux 用戶不能享受 ZFS 及其提供的功能。
本文探究了在 Linux 中使用 ZFS 的兩種方法。第一種使用了用戶空間文件系統(Filesystem in Userspace,FUSE)系統來推動 ZFS 文件系統到用戶空間以便避免許可問題。第二種方法是一個 ZFS 本機埠,用於集成到 Linux 內核,同時避免知識產權問題。
ZFS 簡介
將 ZFS 稱為文件系統有點名不副實,因為它在傳統意義上不僅僅是個文件系統。ZFS 將邏輯卷管理器的概念與功能豐富的和可大規模擴展的文件系統結合起來。讓我們開始先探索一些 ZFS 所基於的原則。首先,ZFS 使用池存儲模型,而不是傳統的基於卷的模型。這意味著 ZFS 視存儲為可根據需要動態分配(和縮減)的共享池。這優於傳統模型,在傳統模型中,文件系統位於卷上,使用獨立卷管理器來管理這些資產。ZFS 內嵌入的是重要功能集(如快照、即寫即拷克隆、連續完整性檢查和通過 RAID-Z 的數據保護)的實現。更進一步,可以在 ZFS 卷的頂端使用您自己最喜愛的文件系統(如 ext4)。這意味著您可以獲得那些 ZFS 的功能,如獨立文件系統中的快照(該文件系統可能並不直接支持它們)。
但是 ZFS 不只是組成有用文件系統的功能集合。相反,它是構建出色文件系統的集成和補充功能的集合。讓我們來看看其中的一些功能,然後再看看它們的一些實際應用。
存儲池
正如前面所討論的,ZFS 合併了卷管理功能來提取底層物理存儲設備到文件系統。ZFS 對存儲池(稱為 zpools)進行操作,而不是直接查看物理塊設備,存儲池構建自虛擬驅動器,可由驅動器或驅動器的一部分物理地進行表示。此外,可以動態構造這些池,甚至這些池正在活躍地使用時也可以。
即寫即拷
ZFS 使用即寫即拷模型來管理存儲中的數據。雖然這意味著數據永遠不會寫入到位(從來沒有被覆蓋),而是寫入新塊並更新元數據來引用數據。即寫即拷有利的原因有多個(不僅僅是因為它可以啟用的快照和克隆等一些功能)。由於從來不覆蓋數據,這可以更簡單地確保存儲永遠不會處於不一致的狀態(因為在新的寫入操作完成以後較早的數據仍保留)。這允許 ZFS 基於事務,且更容易實現類似原子操作等的功能。
即寫即拷設計的一個有趣的副作用是文件系統的所有寫入都成為順序寫入(因為始終進行重新映射)。此行為避免存儲中的熱點並利用順序寫入的性能(比隨機寫入更快)。
數據保護
可以使用 ZFS 的眾多保護方案之一來保護由虛擬設備組成的存儲池。您不但可以跨兩個或多個設備(RAID 1)來對池進行鏡像,通過奇偶校驗來保護該池(類似於 RAID 5),而且還可以跨動態帶區寬度(後面詳細介紹)來鏡像池。基於池中設備數量,ZFS 支持各種不同的的奇偶校驗方案。例如,您可以通過 RAID-Z (RAID-Z 1) 來保護三個設備;對於四個設備,您可以使用 RAID-Z 2(雙重奇偶校驗,類似於 RAID6)。對於更大的保護來說,您可以將 RAID-Z 3 用於更大數量的磁碟進行三重奇偶校驗。
為提高速度(不存在錯誤檢測以外的數據保護),您可以跨設備進行條帶化(RAID 0)。您還可以創建條帶化鏡像(來鏡像條帶化設備),類似於 RAID 10。
ZFS 的一個有趣屬性隨 RAID-Z、即寫即拷事務和動態條帶寬度的組合而來。在傳統的 RAID 5 體系結構中,所有磁碟都必須在條帶內具有其自己的數據,或者條帶不一致。因為沒有方法自動更新所有磁碟,所以這可能產生眾所周知的 RAID 5 寫入漏洞問題(其中在 RAID 集的驅動器中條帶是不一致的)。假設 ZFS 處理事務且從不需要寫入到位,則寫入漏洞問題就消除了。此方法的另外一個便捷性體現在磁碟出現故障且需要重建時。傳統的 RAID 5 系統使用來自該集中其他磁碟的數據來重建新驅動器的數據。RAID-Z 遍歷可用的元數據以便只讀取有關幾何學的數據並避免讀取磁碟上未使用的空間。隨著磁碟變得更大以及重建次數的增加,此行為變得更加重要。
校驗和
雖然數據保護提供了在故障時重新生成數據的能力,但是這並不涉及處於第一位的數據的有效性。ZFS 通過為寫入的每個塊的元數據生成 32 位校驗和(或 256 位散列)解決了此問題。在讀取塊時,將驗證此校驗和以避免靜默數據損壞問題。在有數據保護(鏡像或 AID-Z)的卷中,可自動讀取或重新生成備用數據。
在 ZFS 上校驗和與元數據存儲在一起,所以可以檢測並更正錯位寫入 — 如果提供數據保護(RAID-Z)—。
快照和克隆
由於 ZFS 的即寫即拷性質,類似快照和克隆的功能變得易於提供。因為 ZFS 從不覆蓋數據而是寫入到新的位置,所以可以保護較早的數據(但是在不重要的情況下被標記為刪除以逆轉磁碟空間)。快照 就是舊塊的保存以便及時維護給定實例中的文件系統狀態。這種方法也是空間有效的,因為無需複製(除非重新寫入文件系統中的所有數據)。克隆 是一種快照形式,在其中獲取可寫入的快照。在這種情況下,由每一個克隆共享初始的未寫入塊,且被寫入的塊僅可用於特定文件系統克隆。
可變塊大小
傳統的文件系統由匹配後端存儲(512 位元組)的靜態大小的塊組成。ZFS 為各種不同的使用實現了可變塊大小(通常大小達到 128KB,但是您可以變更此值)。可變塊大小的一個重要使用是壓縮(因為壓縮時的結果塊大小理想情況下將小於初始大小)。除了提供更好的存儲網路利用外,此功能也使存儲系統中的浪費最小化(因為傳輸更好的數據到存儲需要更少的時間)。
在壓縮以外,支持可變塊大小還意味著您可以針對所期望的特定工作量優化塊大小,以便改進性能。
其他功能
ZFS 併入了許多其他功能,如重複數據刪除(最小化數據重複)、可配置的複製、加密、緩存管理的自適應更換緩存以及在線磁碟清理(標識並修復在不使用保護時可以修復的潛在錯誤)。它通過巨大的可擴展性來實現該功能,支持 16 千兆兆個位元組的可定址存儲(264 位元組)。
回頁首
在 Linux 上使用 ZFS
現在您已經了解了 ZFS 背後的一些抽象概念,讓我們在實踐中看看其中的一些概念。本演示使用了 ZFS-FUSE。FUSE 是一種機制,允許您在沒有內核代碼(除 FUSE 內核模塊和現有的文件系統代碼以外)情況下在用戶空間中實現文件系統。該模塊為用戶和文件系統實現提供從內核文件系統介面到用戶空間的橋樑。首先,安裝 ZFS-FUSE 包(下面的演示針對 Ubuntu)。
安裝 ZFS-FUSE
安裝 ZFS-FUSE 很簡單,尤其是在使用 apt
的 Ubuntu 上。下面的命令行安裝了您開始使用 ZFS-FUSE 所需的一切:
$ sudo apt-get install zfs-fuse |
此命令行安裝 ZFS-FUSE 和所有其他依賴包( 我的也需要 libaiol
),為新的程序包執行必要的設置並啟動 zfs-fuse
守護進程。
使用 ZFS-FUSE
在此演示中,您使用環回設備以便在主機操作系統內將磁碟模擬為文件。要開始此操作,請通過 dd
實用程序(參見清單 1)創建這些文件(使用 /dev/zero 作為源)。在創建了四個磁碟映像之後,使用 losetup
將磁碟映像與環路設備關聯在一起。
清單 1. 使用 ZFS-FUSE 的設置
$ mkdir zfstest $ cd zfstest $ dd if=/dev/zero of=disk1.img bs=64M count=1 1+0 records in 1+0 records out 67108864 bytes (67 MB) copied, 1.235 s, 54.3 MB/s $ dd if=/dev/zero of=disk2.img bs=64M count=1 1+0 records in 1+0 records out 67108864 bytes (67 MB) copied, 0.531909 s, 126 MB/s $ dd if=/dev/zero of=disk3.img bs=64M count=1 1+0 records in 1+0 records out 67108864 bytes (67 MB) copied, 0.680588 s, 98.6 MB/s $ dd if=/dev/zero of=disk4.img bs=64M count=1 1+0 records in 1+0 records out 67108864 bytes (67 MB) copied, 0.429055 s, 156 MB/s $ ls disk1.img disk2.img disk3.img disk4.img $ sudo losetup /dev/loop0 ./disk1.img $ sudo losetup /dev/loop1 ./disk2.img $ sudo losetup /dev/loop2 ./disk3.img $ sudo losetup /dev/loop3 ./disk4.img $ |
有了四台設備作為您的 ZFS 塊設備(總大小 256MB),使用 zpool
命令來創建您的池。您可以使用 zpool
命令來管理 ZFS 存儲池,不過您將看到,您可以將其用於各種其他目的。下面的命令要求通過四個設備創建 ZFS 存儲池並通過 RAID-Z 提供數據保護。在此命令後為一個列表請求,以便提供您池中的數據(參見清單 2)。
清單 2. 創建 ZFS 池
$ sudo zpool create myzpool raidz /dev/loop0 /dev/loop1 /dev/loop2 /dev/loop3 $ sudo zfs list NAME USED AVAIL REFER MOUNTPOINT myzpool 96.5K 146M 31.4K /myzpool $ |
您還可以研究池的一些屬性,如清單 3 所示,其代表默認值。對於其他事項,您可以查看可用容量和已使用的部分。(為了簡潔,此代碼已經被壓縮。)
清單 3. 查看存儲池的屬性
$ sudo zfs get all myzpool NAME PROPERTY VALUE SOURCE myzpool type filesystem - myzpool creation Sat Nov 13 22:43 2010 - myzpool used 96.5K - myzpool available 146M - myzpool referenced 31.4K - myzpool compressratio 1.00x - myzpool mounted yes - myzpool quota none default myzpool reservation none default myzpool recordsize 128K default myzpool mountpoint /myzpool default myzpool sharenfs off default myzpool checksum on default myzpool compression off default myzpool atime on default myzpool copies 1 default myzpool version 4 - ... myzpool primarycache all default myzpool secondarycache all default myzpool usedbysnapshots 0 - myzpool usedbydataset 31.4K - myzpool usedbychildren 65.1K - myzpool usedbyrefreservation 0 - $ |
現在,讓我們實際使用 ZFS 池。首先,在您的池中創建目錄,然後在該目錄中啟用壓縮(使用 zfs set
命令)。其次,將文件複製到其中。我已經選擇了大小 120KB 左右的文件來查看 ZFS 壓縮的效果。請注意您的池掛載在根目錄上,因此就像您的根文件系統內的目錄一樣加以處理。一旦複製該文件,您就可以列出它來表示文件已存在(但與原來同樣大小)。通過使用 dh
命令,您可以看到文件大小為原來的一半,這說明 ZFS 已經將其壓縮。您還可以查看 compressratio
屬性,了解您的池有多少已經被壓縮(使用默認壓縮程序,gzip)。清單 4 顯示了該壓縮。
清單 4. 演示 ZFS 壓縮
$ sudo zfs create myzpool/myzdev $ sudo zfs list NAME USED AVAIL REFER MOUNTPOINT myzpool 139K 146M 31.4K /myzpool myzpool/myzdev 31.4K 146M 31.4K /myzpool/myzdev $ sudo zfs set compression=on myzpool/myzdev $ ls /myzpool/myzdev/ $ sudo cp ../linux-2.6.34/Documentation/devices.txt /myzpool/myzdev/ $ ls -la ../linux-2.6.34/Documentation/devices.txt -rw-r--r-- 1 mtj mtj 118144 2010-05-16 14:17 ../linux-2.6.34/Documentation/devices.txt $ ls -la /myzpool/myzdev/ total 5 drwxr-xr-x 2 root root 3 2010-11-20 22:59 . drwxr-xr-x 3 root root 3 2010-11-20 22:55 .. -rw-r--r-- 1 root root 118144 2010-11-20 22:59 devices.txt $ du -ah /myzpool/myzdev/ 60K /myzpool/myzdev/devices.txt 62K /myzpool/myzdev/ $ sudo zfs get compressratio myzpool NAME PROPERTY VALUE SOURCE myzpool compressratio 1.55x - $ |
最後,讓我們看看 ZFS 的自修復功能。請回想在您創建池時,您要求四個設備具有 RAID-Z。通過使用 zpool status
命令您可以檢查池的狀態, 如清單 5 所示。如清單所示,您可以看到池的元素(RAID-Z 1 以及四個設備)。
清單 5. 檢查池狀態
$ sudo zpool status myzpool pool: myzpool state: ONLINE scrub: none requested config: NAME STATE READ WRITE CKSUM myzpool ONLINE 0 0 0 raidz1 ONLINE 0 0 0 loop0 ONLINE 0 0 0 loop1 ONLINE 0 0 0 loop2 ONLINE 0 0 0 loop3 ONLINE 0 0 0 errors: No known data errors $ |
現在,讓我們強制執行一個錯誤到池中。對於此演示來說,轉到後台並損壞組成設備的磁碟文件(disk4.img,通過 loop3
設備顯示在 ZFS 中)。使用 dd
命令將整個設備清零(參見清單 6)。
清單 6. 損壞 ZFS 池
$ dd if=/dev/zero of=disk4.img bs=64M count=1 1+0 records in 1+0 records out 67108864 bytes (67 MB) copied, 1.84791 s, 36.3 MB/s $ |
ZFS 目前未意識到損壞,但是您可以通過請求池的清理,強制池發現問題。如清單 7 所示,ZFS 現在認識到(loop3
設備的)損壞並建議操作以便替換該設備。還請注意在 ZFS 通過 RAID-Z 自我更正時,池仍然在線,您仍然可以訪問您的數據。
清單 7. 清理並檢查池
$ sudo zpool scrub myzpool $ sudo zpool status myzpool pool: myzpool state: ONLINE status: One or more devices could not be used because the label is missing or invalid. Sufficient replicas exist for the pool to continue functioning in a degraded state. action: Replace the device using 'zpool replace'. see: http://www.sun.com/msg/ZFS-8000-4J scrub: scrub completed after 0h0m with 0 errors on Sat Nov 20 23:15:03 2010 config: NAME STATE READ WRITE CKSUM myzpool ONLINE 0 0 0 raidz1 ONLINE 0 0 0 loop0 ONLINE 0 0 0 loop1 ONLINE 0 0 0 loop2 ONLINE 0 0 0 loop3 UNAVAIL 0 0 0 corrupted data errors: No known data errors $ wc -l /myzpool/myzdev/devices.txt 3340 /myzpool/myzdev/devices.txt $ |
根據建議,引入新的設備到您的 RAID-Z 集以便充當新的容器。首先創建新的磁碟映像並通過 losetup
將其表示為設備。請注意此過程類似於將新的物理磁碟添加到集。然後,您使用 zpool replace
用新的設備(loop4
)交換已損壞的設備(loop3
)。檢查池狀態,您可以看到新設備具有一條消息,指示其上重新構建了數據(稱為 resilvering)以及移到那裡的數據量。還請注意池仍保持在線,沒有錯誤(對用戶可見)。最後,再次清理池;在檢查其狀態以後,您將看不到存在問題,如清單 8 所示。
清單 8. 使用 zpool replace 修復池
$ dd if=/dev/zero of=disk5.img bs=64M count=1 1+0 records in 1+0 records out 67108864 bytes (67 MB) copied, 0.925143 s, 72.5 MB/s $ sudo losetup /dev/loop4 ./disk5.img $ sudo zpool replace myzpool loop3 loop4 $ sudo zpool status myzpool pool: myzpool state: ONLINE scrub: resilver completed after 0h0m with 0 errors on Sat Nov 20 23:23:12 2010 config: NAME STATE READ WRITE CKSUM myzpool ONLINE 0 0 0 raidz1 ONLINE 0 0 0 loop0 ONLINE 0 0 0 loop1 ONLINE 0 0 0 loop2 ONLINE 0 0 0 loop4 ONLINE 0 0 0 59.5K resilvered errors: No known data errors $ sudo zpool scrub myzpool $ sudo zpool status myzpool pool: myzpool state: ONLINE scrub: scrub completed after 0h0m with 0 errors on Sat Nov 20 23:23:23 2010 config: NAME STATE READ WRITE CKSUM myzpool ONLINE 0 0 0 raidz1 ONLINE 0 0 0 loop0 ONLINE 0 0 0 loop1 ONLINE 0 0 0 loop2 ONLINE 0 0 0 loop4 ONLINE 0 0 0 errors: No known data errors $ |
此簡短演示探究了通過文件系統進行的卷管理的整合,並展示了管理 ZFS(即使是故障時)有多簡單。
回頁首
其他 Linux-ZFS 可能性
FUSE 中 ZFS 的優點是易於開始使用 ZFS,但是它的缺點是效率低。這種效率上的缺點是每個 I/O 都要求多個用戶內核轉換的結果。但是考慮到 ZFS 的流行,有另外一種提供更好性能的選項。
針對 Linux 內核的 ZFS 本地埠正在 Lawrence Livermore 國家實驗室中處於順利開發當中。雖然此埠仍然缺乏一些元素,如 ZFS 攜帶型操作系統介面(適用於 UNIX®) 層,但是這正在開發中。其埠提供大量有用的功能,尤其是當您有興趣與 Lustre 一起使用 ZFS 時。(要了解更多細節,參閱 參考資料。)
回頁首
前景展望
希望本文已經引起您進一步挖掘 ZFS 的慾望。從早前的演示中,您可以容易地設置 ZFS 並在大多數 Linux 發行版中運行 — 甚至是在擁有一些限制的內核中。雖然快照和克隆等主題並未在此處演示,但是 參考資料 部分提供了有關此主題的有趣的文章的鏈接。最後,Linux 和 ZFS 是最先進的技術,很難將它們分開。
參考資料
學習
[火星人 ] 在 Linux 上運行 ZFS已經有1421次圍觀