群暉和飛牛 NAS 如何用 Btrfs + jdupes CoW 去重節省空間

介紹群暉和飛牛 NAS 上如何利用 Btrfs 的 CoW 能力,透過 jdupes 對重複檔案做區塊級去重,節省空間並避免硬連結帶來的修改風險。

如果 NAS 裡經常保存影視檔案、備份包、安裝映像、照片匯出目錄,重複檔案很容易不知不覺占掉幾百 GB 甚至幾 TB。傳統做法通常是刪除重複檔案,或者把重複檔案改成硬連結,但這兩種方式都不太適合 NAS 的長期儲存。

更穩妥的方式是:在支援 CoW 的檔案系統上,用 jdupes 做區塊級去重。

對群暉和飛牛這類 NAS 使用者來說,如果儲存卷使用的是 Btrfs,就可以利用 jdupes -B 呼叫檔案系統底層能力,讓重複檔案共享同一份物理資料區塊。檔案在目錄裡看起來仍然是獨立檔案,但底層只占一份空間。

CoW 去重和硬連結有什麼區別

硬連結的邏輯是:多個路徑指向同一個 inode。

這確實能省空間,但也有明顯問題:如果某個程式修改了其中一個檔案,其他硬連結路徑看到的內容也會一起變化。對媒體庫、同步目錄、照片管理和備份目錄來說,這種行為很容易埋坑。

Btrfs 的 CoW 去重不同。

它的邏輯是:多個獨立檔案可以共享相同的資料區塊;一旦其中一個檔案被修改,檔案系統會把被修改的部分寫到新的資料區塊,其他檔案不受影響。

也就是說,CoW 去重後:

  • 檔案路徑仍然互相獨立;
  • 刪除其中一個檔案不會刪除其他檔案;
  • 修改其中一個檔案不會改動其他檔案;
  • 重複部分只在磁碟上占用一份空間。

這正是 jdupes -B 比硬連結去重更適合 NAS 的原因。

適合使用的場景

比較適合跑 CoW 去重的目錄包括:

  • 影視庫中重複下載的劇集和電影;
  • 不同目錄裡的安裝包、ISO、壓縮包;
  • 多次匯出的照片或影片素材;
  • 備份軟體產生的重複大檔案;
  • 手工整理時複製出來的臨時目錄。

不太建議一上來就對整個系統卷執行。更穩的做法是先選一個使用者資料目錄,比如:

1
2
3
/volume1/video/
/volume1/photo/
/volume1/data1/aaa/

先小範圍測試,確認命令、排除規則和節省效果都符合預期,再擴大範圍。

基礎命令

在 Btrfs 目錄上使用 jdupes 做 CoW 去重,核心參數是 -B

1
jdupes -r -B "/volume1/data1/aaa/"

參數含義:

  • -r:遞迴掃描子目錄;
  • -B:對找到的重複檔案執行 Btrfs/CoW 去重,而不是建立硬連結;
  • "/volume1/data1/aaa/":要掃描的目標目錄。

這裡最關鍵的是 -B。它會讓 jdupes 呼叫檔案系統支援的去重能力,通常對應 reflink、clone 或 dedupe range 這類底層介面。

群暉建議排除 @eaDir 和 #recycle

在群暉上,不建議把 @eaDir#recycle 放進掃描範圍。

@eaDir 是群暉系統產生的隱藏目錄,裡面通常保存縮圖、媒體索引、延伸屬性和套件相關快取。它數量多、檔案小,掃描成本高,收益很低,還可能干擾群暉自己的索引服務。

#recycle 是共享資料夾的資源回收筒。裡面的檔案本來就準備被清理,對它們去重意義不大,還會讓結果變得難判斷。

所以在群暉上,更推薦把這兩個目錄排除掉。

不同版本的 jdupes-X 參數支援不完全一樣。有些教學會寫成:

1
jdupes -r -B -X "req:*/@eaDir/*" -X "req:*/#recycle/*" "/volume1/data1/aaa/"

但部分群暉環境會報錯:

1
Invalid extfilter filter name was specified

如果你的 jdupes -X 說明裡顯示支援 nostr:text_string,可以使用更相容的寫法:

1
jdupes -r -B -X nostr:/@eaDir/ -X nostr:/#recycle/ "/volume1/data1/aaa/"

含義很直接:

  • -X nostr:/@eaDir/:排除路徑中包含 /@eaDir/ 的檔案;
  • -X nostr:/#recycle/:排除路徑中包含 /#recycle/ 的檔案。

如果目標路徑包含中文或空格,一定要加雙引號:

1
jdupes -r -B -X nostr:/@eaDir/ -X nostr:/#recycle/ "/volume1/photo/视频工作/"

飛牛 NAS 上怎麼理解

飛牛 NAS 如果使用 Btrfs 儲存池,思路和群暉類似:重點仍然是確認目標目錄位於 Btrfs 檔案系統,並使用 jdupes -B 做 CoW 去重。

差別在於系統隱藏目錄名稱可能不同。群暉常見的是 @eaDir#recycle,飛牛需要按實際目錄結構決定排除規則。

建議先執行:

1
find "/你的目标目录" -maxdepth 2 -type d

看一下是否存在系統快取、資源回收筒、索引目錄或應用資料目錄。真正值得去重的通常是使用者資料裡的大檔案,而不是系統產生的小快取。

如何確認 CoW 去重成功

不要只看 ls -l。CoW 去重後,檔案邏輯大小不會變,目錄裡看起來還是多個完整檔案。

更可靠的驗證方式有三種。

1. 看 jdupes 輸出

執行過程中,如果看到類似輸出,通常說明重複檔案已經被識別並處理:

1
2
3
[SRC] /volume1/data1/aaa/1/file.mkv
====> /volume1/data1/aaa/2/file.mkv
====> /volume1/data1/aaa/3/file.mkv

[SRC] 表示源檔案,====> 後面的檔案表示被合併到同一份底層資料區塊上。檔案仍然獨立存在,但物理空間已經被壓縮。

2. 對比 Btrfs 空間變化

在去重前後分別執行:

1
sudo btrfs filesystem usage /volume1/data1/aaa/

重點看這幾個欄位:

1
2
3
Used:
Free (estimated):
Data,single: Used:

如果去重生效,一般會看到:

  • Used 減少;
  • Data,single: Used 減少;
  • Free (estimated) 增加。

比如去重前 Used8.44TiB,去重後下降到 8.20TiB,哪怕只減少幾十 GB,也說明 CoW 去重已經在釋放物理空間。

3. 使用 compsize 查看真實占用

如果系統能安裝 compsize,可以更直觀看到 Btrfs 壓縮和去重後的真實占用:

1
sudo compsize "/volume1/data1/aaa/"

它比普通 du 更適合理解 Btrfs 上的實際占用情況。

安全執行建議

建議按下面順序操作:

  1. 先確認目標目錄在 Btrfs 卷上;
  2. 先對一個小目錄測試,不要直接掃整個卷;
  3. 排除系統隱藏目錄、資源回收筒和應用快取目錄;
  4. 路徑包含中文或空格時使用雙引號;
  5. 去重前記錄一次 btrfs filesystem usage
  6. 去重後再次記錄並對比 UsedFree (estimated)
  7. 不確定參數含義時,先執行 jdupes --help 看本機版本支援的過濾器。

最推薦的群暉命令可以從這一條開始:

1
jdupes -r -B -X nostr:/@eaDir/ -X nostr:/#recycle/ "/volume1/data1/aaa/"

如果你的 jdupes 版本不支援 nostr,就根據 jdupes -Xjdupes --help 的輸出調整過濾參數。

小結

Btrfs + jdupes -B 的價值在於:不用刪除檔案,也不用把檔案改成硬連結,就能讓重複內容共享底層物理空間。

對群暉、飛牛這類 NAS 使用者來說,它特別適合處理重複影視檔案、備份檔案和大體積素材目錄。真正需要注意的是掃描範圍和排除規則:優先處理使用者資料,避開系統快取和資源回收筒,去重前後用 Btrfs 工具對比空間變化。

簡單說,想安全省空間,優先記住這一句:

1
jdupes -r -B -X nostr:/@eaDir/ -X nostr:/#recycle/ "/你的Btrfs数据目录/"
记录并分享
使用 Hugo 建立
主題 StackJimmy 設計