歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> 折騰了一下 neptune 上的 ZFS

折騰了一下 neptune 上的 ZFS

日期:2017/2/28 15:31:36   编辑:Linux教程

我一直是非常反對重裝系統的。從技術上說,今天的折騰並不算是重裝系統,不過因為把機器上所有的數據(是的,文件系統全部都拆掉重建了)都重寫了一遍,所以還是算做了一次吧。

緣起
在采購 家裡的路由器 的時候,選擇了 WD 的 AV-25【1】 系列硬盤。我選的那款硬盤使用的是新式的 AF (4kiB扇區)格式。

FreeBSD 使用的主流文件系統 UFS 和 ZFS,以及 ahci(4) 驅動都 直接支持 4kiB 扇區。但是,目前市面上的AF硬盤,為了與先前的 BIOS 和操作系統(主要是 Windows XP)兼容,對於 ATA IDENTIFY 的回應,原先返回扇區尺寸的位置變成了邏輯扇區尺寸,這種做法俗稱512e,即硬盤通過固件或其他方式模擬山區尺寸為512字節,並處理相關的回寫操作。

以512字節為單位進行讀寫時,在AF格式的硬盤上是低效的。FreeBSD的 ahci(4) 驅動和對應的 ada(4) 驅動會設置 stripesize 以反映驅動器采用的實際物理扇區尺寸,但文件系統並不直接識別這個尺寸。

對於 ZFS 而言,其扇區尺寸是在創建時以 ashift 值寫死的,目前在命令行沒有辦法指定這個值,也不能在創建 ZFS 之後修改。如果修改內核令其使用 GEOM 的 stripesize 來產生 ashift,對 AF 硬盤則會出現內核得到的 ashift 比先前已經存在的 ashift 大,從而導致 ZFS 無法識別的問題(如果創建 ZFS 時已經使用了更大的 ashift 則沒有關系)。因此,必須想辦法讓 ZFS 在創建時就知道扇區尺寸是 4KiB。

FreeBSD 5.3-RELEASE 時新增了一個調試用的 GEOM class ---- gnop。可以用它來封裝其他 GEOM 對象,並改變扇區尺寸,方法是 gnop create -S 4096 /dev/gpt/store (此處 /dev/gpt/store 是一個按 4k 對齊的 GPT 分區的 label)。gnop會產生一個新的設備節點,/dev/gpt/store.nop,其向系統匯報的扇區尺寸是我們指定的 4096 字節,而不是驅動器匯報的邏輯扇區尺寸 512 字節。

使用這個設備節點創建的 ZFS 就會采用正確的 ashift 值了。

使用 zdb -C pool名字可以檢查 ashift 值:對於扇區尺寸為 512 字節的 zpool,其 ashift 是 9,而我們希望的 ashift 值是12。

gnop節點在系統重啟以後會消失,但 ZFS 會記住 ashift,因此並不會導致問題。此處也可以 zpool export,gnop destroy /dev/gpt/store.nop 然後再 zpool import 來驗證。

經測試,ZFS在知道正確的扇區尺寸以後,持續寫操作的性能可以提高至少一倍。

折騰
作為一個不折騰就會死星人,一倍的性能改善是有非常大的誘惑力的。因為我有兩塊硬盤,總容量剛好用到45%而且也沒做成 mirror 或 stripe,所以正好倒騰一下。

首先是刪除不必要的數據。凡是在家中有備份的數據一律刪除(我自己的筆記本的系統文件和日常工作的數據備份共騰出約70GB)。

然後首先是把所有的數據復制到系統所在的 zpool 上。

制作快照:

zfs snapshot -r backup@pre-4k; zfs send -R backup@pre-4k | zfs receive -Fvd system/backup

確認備份可用且無數據校驗錯誤之後,撤銷備份卷:

zpool destroy backup

友情提示:這一步請在意識清醒的時候做。

然後為備份卷創建gnop設備:gnop create -S 4096 /dev/gpt/backup

由於之前創建這套系統時沒有考慮引導部分的冗余,因此希望在重建系統時加入這方面的考慮。用gpart刪掉備份卷所在分區,創建一個4GiB的freebsd-zfs類型的分區,剩余的空間作為另一個freebsd-zfs分區,並標記為新的備份卷設備:

gpart delete -i 3 ada1; gpart add -s 8388608 -t freebsd-zfs -l boot1 ada1; gpart add -t freebsd-zfs -l backup ada1

此處3、ada1是我的備份卷對應的分區編號和設備。boot1因為要做成mirror,因此暫時先不用。

重新創建備份卷:

zpool create backup /dev/gpt/backup.nop

用zdb確認ashift已經是12;

卸下備份卷並取消gnop設備:

zpool export backup; gnop destroy /dev/gpt/backup.nop

重新加載備份卷:

zpool import backup

此時可以再次用zdb檢查ashift值(仍是12)。

從系統卷中恢復全部dataset

zfs send -R system/backup@pre-4k | zfs receive -Fvd backup

用類似的方法將系統卷復制到備份卷上。

由於系統卷在引導時一直在占用狀態,因此不能直接在系統中將其卸下。使用插在主板上的USB stick上的系統引導之後:

刪除系統卷所在的分區,並重新劃分:

gpart delete -i 3 ada0; gpart add -s 8388608 -t freebsd-zfs -l boot0 ada0; gpart add -t freebsd-zfs -l neptune ada0

建立一個普通的系統卷【2】,使用兩塊盤上的boot0、1分區做成mirror:

zpool create -O canmount=off -O atime=off -O setuid=off system mirror /dev/gpt/boot[01]

建立用於引導系統的根dataset:

zfs create -m legacy -o compression=on -o setuid=on system/root

加載backup卷:

zpool import -R /mnt

掛載backup/system/root並將內容復制過來:

mkdir /tmp/src /tmp/dst; mount -t zfs backup/system/root /tmp/src; mount -t zfs system/root /tmp/dst; cd /tmp/src; tar cf - . | tar xf - -C /tmp/dst/

調整的具體操作在此不再贅述。簡要說明:

原先的 system 卷包含了引導系統和日常運行的所有數據。此次調整將日常運行的其他數據獨立到一個新的卷 neptune 上,以方便維護和備份(系統卷很少會出現變化,而其出現問題的修起來很麻煩,所以變為mirror卷)
除了system卷之外,所有的mountpoint均為canmount=off或inherit上層。
/usr/local、/home等拆到 neptune 卷上以方便備份。
創建了必要的符號鏈接。
遷回過程比預想的快的多(另外針對使用ashift=12和ashift=9兩種情況都進行了測試)。

遷移過程中遇到的問題和教訓
在拆分時發現之前的一個系統用戶的 /home 目錄不是 zfs,而是直接放在了根目錄中。

在使用 zfs receive 恢復快照時,由於 -R 會采用完整的路徑,因此單獨創建了一個 recv 目錄,然後將上層dataset以 rename 的方式放回 system 卷對應的位置時,由於上層 dataset 並沒有從源處接受,導致 /usr 被空目錄遮蓋。遠程 root 登錄之後 zfs set canmount=off system/usr 後恢復。

由於事先做好了計劃並留有備份,整個遷移過程只導致了短暫停機,而沒有損失數據。

平時要多看代碼和做性能測試,特別是在數據還不太多的時候。數百GB的數據即使只是在本地跑一遍也是很費時的操作。

其他說明事項
【1】請特別注意:WD的AV系列硬盤是針對流媒體而不是普通的數據應用設計的,在遇到數據錯誤時並不會像普通硬盤那樣反復重試。在我的設計中采用的是異地冗余備份,如果只打算裝一塊硬盤,或不使用帶校驗功能的文件系統如ZFS,則不推薦這一系列。

【2】系統卷中的文件主要是引導系統時用到的,采用傳統的512字節扇區。

Copyright © Linux教程網 All Rights Reserved