近期,DeepSeek 開源了其檔案系統 Fire-Flyer File System (3FS),使得檔案系統這一有著 70 多年曆時的“古老”的技術,又獲得了各方的關注。在 AI 業務中,企業需要處理大量的文字、影像、影片等非結構化資料,還需要應對資料量的爆炸式增長,分散式檔案系統因此成為 AI 訓練的關鍵儲存技術。
本文旨在透過深入分析 3FS 的實現機制,並與 JuiceFS 進行對比,以幫助使用者理解兩種檔案系統的區別及其適用場景。同時,我們將探討 3FS 中的值得借鑑的創新技術點。
01 架構對比
3FS
3FS[1]
(Fire-Flyer File System) 是一款高效能的分散式檔案系統,專為解決 AI 訓練和推理工作負載而設計,該系統使用高效能的 NVMe 和 RDMA 網路提供共享儲存層。3FS 由 DeepSeek 在 2025 年 2 月開源。
3FS 主要包括以下模組:
-
• 叢集管理服務(Cluster Manager)
-
• 元資料服務(Metadata Service)
-
• 儲存服務(Storage Service)
-
• 客戶端 (FUSE Client、Native Client)

3FS 架構
所有模組透過 RDMA 網路通訊。元資料服務和儲存服務向叢集管理服務傳送心跳訊號。叢集管理服務負責處理成員變更,並將叢集配置分發給其他服務和客戶端。為了提高系統的可靠性和避免單點故障,會部署多個叢集管理服務,其中一個被選為主節點。當主節點發生故障時,另一個管理器會被提升為主節點。叢集配置通常儲存在可靠的分散式服務中,例如 ZooKeeper 或 etcd。
當進行檔案元資料操作(例如開啟或建立檔案/目錄),請求被髮送到元資料服務,以實現檔案系統語義。元資料服務有多個,並且是無狀態的,它們不直接儲存檔案元資料,而是依賴支援事務的鍵值資料庫 FoundationDB 來儲存這些資料。因此,客戶端可以靈活地連線到任意元資料服務。這種設計使得元資料服務可以在沒有狀態資訊的情況下獨立運作,進而增強了系統的可伸縮性和可靠性。
每個儲存服務管理若干本地 SSD,並提供 chunk 儲存介面。儲存服務採用 CRAQ ( Chain Replication with Apportioned Queries)來確保強一致性。3FS 中儲存的檔案被拆分為預設 512K 大小相等的塊,並在多個 SSD 上進行復制,從而提高資料的可靠性和訪問速度。
3FS 客戶端提供兩種接入方式:FUSE Client 和 Native Client。FUSE Client 提供常見 POSIX 介面的支援,簡單易用。Native Client 提供更高的效能,但是使用者需要呼叫客戶端 API ,具有一定的侵入性,下文我們還將對此作更詳盡的解析。
JuiceFS
JuiceFS 是一個雲原生分散式檔案系統,其資料儲存在物件儲存中。
社群版[2]
可與多種元資料服務整合,適用場景廣泛,於 2021 年在 GitHub 開源。企業版專為高效能場景設計,廣泛應用於大規模 AI 任務,涵蓋生成式 AI、自動駕駛、量化金融和生物科技等。
JuiceFS 檔案系統包括三部分組成:
-
• 元資料引擎:用於儲存檔案元資料,包括常規檔案系統的元資料和檔案資料的索引。
-
• 資料儲存:一般是物件儲存服務,可以是公有云的物件儲存也可以是私有部署的物件儲存服務。
-
• JuiceFS 客戶端:提供 POSIX(FUSE)、Hadoop SDK、CSI Driver、S3 閘道器等不同的接入方式。

JuiceFS 社群版架構圖
架構差異
從模組劃分上看兩個檔案系統差異不大,都採用了元資料與資料分離的設計,各個模組功能也較類似。不同於 3FS 和 JuiceFS 企業版,JuiceFS 社群版相容多種開源資料庫儲存元資料,對元資料的操作都封裝在客戶端,使用者不需要再單獨運維一個無狀態的元資料服務。
儲存模組
3FS 使用大量本地 SSD 進行資料儲存,為了保證資料儲存的一致性,3FS 使用 CRAQ 這一簡潔的資料一致性演算法 。幾個副本被組成一個 Chain,寫請求從 Chain 的 Head 開始,一直到達 Chain 的 Tail 時返回寫成功應答。讀請求可以傳送到 Chain 的所有副本,如果讀到髒節點的資料,該節點會聯絡 Tail 節點檢查狀態。如下圖所示。

CRAQ 一致性演算法
資料的寫入是按順序逐節點傳遞,因此會帶來比較高的延時。如果 Chain 當中的某個副本不可用, 3FS 會把這個副本移到 Chain 的末尾,等副本可用的時候再做恢復。恢復的時候需要把整個 Chunk 的內容複製到這個副本,而非使用不可用期間的增量資料。如果要做到同步寫所有副本和增量恢復資料,那寫的邏輯會複雜非常多,比如 Ceph 使用 pg log 保證資料一致性。儘管 3FS 這種設計會導致寫延遲,但是對於以讀為主的 AI 應用場景,影響不大。
JuiceFS 利用物件儲存作為資料儲存解決方案,從而可享有物件儲存帶來的若干優勢,如資料可靠性、一致性等。儲存模組提供了一組用於物件操作的介面,包括 GET/PUT/HEAD/LIST 等,使用者可以根據自己的需求對接具體的儲存系統。比如不同雲廠商的物件儲存,也可以選擇私有部署的物件儲存比如 MinIO、Ceph RADOS 等系統。社群版 JuiceFS 提供本地快取來應對 AI 場景下的頻寬需求,JuiceFS 企業版使用分散式快取滿足更大的聚合讀頻寬的需求。
元資料模組
在 3FS 中,檔案的屬性以 KV 的形式儲存在元資料服務中。該服務是一個無狀態的高可用服務,依靠 FoundationDB 做支撐。FoundationDB 是 Apple 開源的優秀分散式 KV 資料庫,具有很高的穩定性。FoundationDB 所有鍵值使用 Key 做全域性排序,然後均勻拆分到不同的節點上。
為了最佳化 list 目錄的效率,3FS 使用字元 “DENT” 字首加父目錄 inode 號和名字作為 dentry 的 Key。Inode 的 Key 是透過將 "INOD" 字首與 inode ID 連線而構造的,其中 inode ID 採用小端位元組序編碼,以便將 inodes 分佈到多個 FoundationDB 節點上。這個設計與 JuiceFS 使用的 TKV(Transactional Key-Value Database)[3] 進行元資料服務的儲存方式類似。
JuiceFS 社群版的元資料模組,與儲存模組類似也提供一組操作元資料的介面,可以接入不同的元資料服務,比如 Redis,TiKV 等 KV 資料庫,MySQL,PostgreSQL 等關係型資料庫,也可以使用 FoundationDB。JuiceFS 企業版使用自研高效能元資料服務,可根據負載情況來平衡資料和熱點操作,以避免大規模訓練中元資料服務熱點集中在某些節點的問題(比如因為頻繁操作臨近目錄檔案的元資料引起)。
客戶端
3FS 的客戶端除了提供 FUSE 操作外,還提供了一組 API 用於繞過 FUSE 直接操作資料,也就是 Native Client,介面的呼叫方式有點類似於 Linux AIO。這組 API 的作用是避免使用 FUSE 模組帶來的資料複製,從而減少 I/O 延遲和對記憶體頻寬的佔用。下面將詳細解析這組 API 如何實現使用者程序與 FUSE 程序之間的零複製通訊。
3FS 透過
hf3fs_iov
儲存共享記憶體的大小,地址和其他一些屬性,使用 IoRing
在兩個程序間通訊。
3FS NATIVE Client API
當用戶呼叫介面,建立
hf3fs_iov
時,會在 /dev/shm
上分配記憶體,並建立一個指向這個共享記憶體的軟連結,軟連結的地址位於 /mount_point/3fs-virt/iovs/
,這是個虛擬目錄。3FS FUSE 程序收到建立軟連結請求,並且發現它的地址位於上述虛擬目錄後,就會根據軟連結的名字解析出這塊共享記憶體的相關引數,並將記憶體的地址註冊到所有 RDMA 裝置(除了 IORing
)。ibv_reg_mr
返回的結果被存在 RDMABuf::Inner
資料結構中,用於後續傳送 RDMA 請求。同時,
IORing
的記憶體也使用 hf3fs_iov
儲存,只是在建立對應的軟連結時,檔名中會有更多的 IORing
相關的資訊。如果 FUSE 程序發現這個記憶體是用於建立 IORing
,也會在它的程序內建立對應的 IORing
。這樣設定之後,使用者程序和 FUSE 程序就可以訪問相同的 IORing
了。程序間協作方面,3FS 在
/mount_point/3fs-virt/iovs/
目錄中建立 3 個不同的虛擬檔案用於共享 3 個不同優先順序的提交訊號量 (submit sem ),使用者程序將請求放到 IORing
後使用這些訊號量通知 FUSE 程序有新的請求。 IORing
尾部包含請求完成訊號量,FUSE 程序透過呼叫 sem_post
通知使用者程序 IORing
上有新的請求完成。以上整個機制確保了兩個程序間的高效資料通訊和操作同步。3FS 的 FUSE 客戶端實現了檔案和目錄的基本操作,而 JuiceFS FUSE 客戶端的實現更加全面。比如,在 3FS 檔案系統中檔案的長度是最終一致的,這意味著在寫的過程中使用者可能訪問到不正確的檔案長度。而 JuiceFS 在每次成功上傳物件後會立即更新檔案長度。此外,JuiceFS 還提供了以下這些常用的高階檔案系統功能:
-
• 支援 BSD 鎖(flock)和 POSIX 鎖(fcntl)
-
• 支援
file_copy_range
介面 -
• 支援
readdirplus
介面 -
• 支援
fallocate
介面
除了 FUSE 客戶端,JuiceFS 還提供 Java SDK,S3 Gateway,CSI Driver 等接入方式。企業版還提供 Python SDK,Python SDK 將 JuiceFS 客戶端在使用者程序中執行,避免了透過 FUSE 導致的額外效能開銷。具體見文件:Python SDK[4]。
02 檔案分佈對比
3FS 檔案分佈
3FS 將每個檔案分成固定長度的 chunk,每個 chunk 位於一個上文提到的鏈上( CRAQ 演算法)。使用者使用 3FS 提供的一個指令碼,生成一個 chain table。然後將這個表提交到元資料服務。建立新檔案時,系統會從表中選取特定數量的 chain (數量由 stripe 定義),並將這些 chain 的資訊存入檔案的元資料中。
因為 3FS 中的 chunk 是固定的,客戶端只需要獲取一次 inode 的 chain 資訊,就可以根據檔案 inode 和 I/O 請求 的 offset,length 計算出這個請求位於哪些 chunk 上,從而避免了每個 I/O 都從資料庫查詢的需求。可以透過
offset/chunk_size
得到 chunk 的索引。而 chunk 所在的 chain 的索引就是 chunk_id%stripe
。有了 chain 的索引就可以得到 chain 的詳細資訊(比如這個 chain 由哪些 target 組成)。然後,客戶端根據路由資訊將 I/O 請求傳送到相應的儲存服務。儲存服務收到寫請求後以 copy-on-write (COW)的方式將資料寫入新的位置。原來的資料在引用資料清零前仍然是可讀的。為了應對資料不平衡問題,每個檔案的第一個 chain 按照輪詢( round roubin) 的方式選擇。比如當 stripe 為 3 時,建立一個檔案,其選擇的 chain 為:chain0,chain1,chain2。那麼下一個檔案的 chain 為:chain1,chain2 和 chain3。系統會將選擇的 3 個 chain 做隨機排序,然後儲存到元資料中。下圖為 stripe 為 3 時一個檔案的分佈示例,chain 隨機排序後的順序是:1,3,2。

3FS 檔案分佈
JuiceFS 檔案分佈
JuiceFS 按照 Chunk、Slice、Block 的規則進行資料塊管理。每個 Chunk 的大小固定為 64M,主要用於最佳化資料的查詢和定位。實際的檔案寫入操作則在 Slice 上執行,每個 Slice 代表一次連續的寫入過程,屬於特定的 Chunk,並且不會跨越 Chunk 的邊界,因此長度不超過 64M。Chunk 和 Slice 主要是邏輯上的劃分,而 Block(預設大小為 4M)則是物理儲存的基本單位,用於在物件儲存和磁碟快取中實現資料的最終儲存。更多細節可以參考官網介紹[5]。

JuiceFS 檔案分佈
JuiceFS 中的 Slice 是在他檔案系統中不常見的一個結構。主要功能是記錄檔案的寫入操作,並在物件儲存中進行持久化。物件儲存不支援原地檔案修改,因此,JuiceFS 透過引入 Slice 結構允許更新檔案內容,而無需重寫整個檔案。這與 Journal File System 有些類似,其中寫入操作僅建立新物件,而不是覆蓋現有物件。修改檔案時,系統會建立新的 Slice,並在該 Slice 上傳完畢後更新元資料,從而將檔案內容指向新的 Slice。被覆蓋的 Slice 內容隨後透過非同步壓縮過程從物件儲存中刪除,導致在某些時刻物件儲存的使用量會暫時超過檔案系統實際使用量。
此外,JuiceFS 的所有 Slice 均為一次性寫入,這減少了對底層物件儲存一致性的依賴,並大大簡化了快取系統的複雜度,使資料一致性更易於保證。這種設計還為實現檔案系統的零複製語義提供了便利,支援如 copy_file_range 和 clone 等操作。
03 3FS RPC (Remote Procedure Call) 框架
3FS 使用 RDMA 作為底層網路通訊協議,目前 JuiceFS 尚未支援,下面對此做一些分析。
3FS 透過實現一個 RPC 框架,來完成對底層 IB 網路的操作。除了網路操作外,RPC 框架還提供序列化,小包合併等能力。因為 C++ 不具有反射能力,所以 3FS 還透過模版實現了一個反射庫,用於序列化 RPC 使用的 request、response 等資料結構。需要被序列化的資料結構只需要使用特定的宏定義需要序列化的屬性。RPC 呼叫都是非同步完成的,所以序列化後的資料只能從堆上分配,等待呼叫完成後再釋放。為了提高記憶體的分配和釋放速度,分配物件都使用了快取。3FS 的快取有兩部份組成,一個 TLS 佇列和一個全域性佇列。從 TLS 佇列獲取快取時不需要加鎖;當 TLS 快取為空時就得加鎖,從全域性佇列中獲取快取。所以在最優情況下,獲取快取是不需要加鎖的。
與 I/O 請求的負載不同,快取物件的記憶體都未註冊到 RDMA 裝置中。因此,當資料到達 IBSocket 後,會被複製到一個在 IB 設備註冊過的緩衝區中。多個 RPC 請求可能被合併為一個 IB 請求傳送到對端。下圖為 FUSE Client 呼叫 Meta 服務的 RPC 過程。

3FS FUSE Client 呼叫 Metadata服務的 RPC 過程
04 特性對比

05 總結
大規模 AI 訓練中最主要的需求是高讀頻寬,為此 3FS 採用了效能優先的設計策略,將資料儲存在高速磁碟上,並且使用者需要自行管理底層資料儲存。這種方法提升了效能,但成本較高,維護也更繁重。此外,為了充分發揮底層硬體的效能,其架構實現了客戶端到網絡卡的零複製,利用共享記憶體和訊號量減少 I/O 延遲和記憶體頻寬佔用。此外,透過帶 TLS 的 I/O buffer pool 和合併網絡請求,3FS 增強了小 I/O 和檔案元資料操作的能力,並引入了效能更優的 RDMA 技術。我們將繼續關注 3FS 在效能最佳化方面的進展,並探索如何將這些技術應用於我們的場景中。
JuiceFS 使用物件儲存作為底層資料儲存,使用者因此可大幅降低儲存成本並簡化維護工作。為了滿足 AI 場景的對讀效能的需求,JuiceFS 企業版引入了分散式快取、分散式元資料服務和 Python SDK,從而提高檔案系統的效能和擴充套件能力,並同時兼顧低儲存成本。在接下來發布的 v5.2 企業版中,在 TCP 網路中實現了零複製,進一步提升資料傳輸效率。
JuiceFS 提供完整的 POSIX 相容性和成熟活躍的開源生態,適應更廣泛的使用場景,並支援Kubernetes CSI,極大簡化了雲平臺的部署和運維工作。此外,JuiceFS 還提供了 Quota、安全管理和資料災備等多項企業級管理功能,讓企業可以更便捷地在生產環境中部署和應用 JuiceFS。
引用連結
[1]
3FS:
https://github.com/deepseek-ai/3FS[2]
社群版:
https://github.com/juicedata/juicefs[3]
TKV(Transactional Key-Value Database):
https://juicefs.com/docs/zh/community/internals/#tkv[4]
Python SDK:
https://juicefs.com/docs/zh/cloud/deployment/python-sdk/[5]
官網介紹:
https://juicefs.com/docs/zh/community/architecture
關於作者

劉慶
Juicedata 核心系統開發工程師