天天看點

ByteFUSE 的演進與落地

作者:位元組跳動技術團隊
ByteFUSE 的演進與落地
ByteFUSE是ByteNAS團隊和STE團隊合作研發的一個項目,因其具有高可靠性、極緻的性能、相容Posix語義以及支援豐富的使用場景等優點而被業務廣泛使用。目前承接了線上業務ES,AI訓練業務,系統盤業務,資料庫備份業務,消息隊列業務,符号表業務以及編譯業務等,位元組内部部署機器和日常挂載點均已達到萬級規模,總吞吐近百GB/s,容量十幾PB,其性能與穩定性能夠滿足業務需求。

背景

ByteNAS是一款全自研、高性能、高擴充,多寫多讀、低延遲時間并且完全相容Posix語義的分布式檔案系統,目前支撐了位元組内部AI訓練,資料庫備份,線上ES等多個關鍵業務,也是未來雲上NAS主打的産品形态。早期ByteNAS對外提供服務使用的是NFS協定,其依賴TTGW四層負載均衡器将外部流量以TCP連接配接的粒度均衡到連接配接的多台Proxy,使用者使用TTGW提供的VIP并進行挂載即可與多台Proxy中一台進行通信。如果目前通信的Proxy因為機器當機等原因挂掉後,TTGW内部探測心跳逾時會觸發Failover機制,自動将來自該Client的請求Redirect到新的活着的Proxy,該機制對用戶端是完全透明的。但是使用TTGW具有以下缺點:

  • 無法支援大吞吐場景: 使用者的吞吐不僅受限于TTGW叢集本身吞吐的限制,而且受限于NFS協定單次讀寫1MB的限制。另外NFS是單TCP連接配接,同時核心slot并發請求也有限制,這會導緻吞吐受限以及中繼資料和資料互相影響
  • 額外的網絡延遲: 使用者通路ByteNAS多兩跳網絡(使用者側NFS Client -> TTGW -> Proxy -> ByteNAS)
  • 額外的機器成本: 需要TTGW以及Proxy等機器資源
  • 定制化業務需求以及性能優化比較困難: 受限于核心NFS Client,NFS協定以及TTGW的影響,其定制化需求以及性能優化比較困難

為了解決以上問題,ByteFUSE應運而生。ByteFUSE是一套基于使用者态檔案系統(FUSE)架構接入ByteNAS的解決方案,通過ByteNAS SDK直連ByteNAS叢集,不僅滿足了低延遲的目标,同時也解決了協定吞吐受限的問題。除此之外,由于部分檔案系統邏輯上移到了使用者态,對于問題排查,功能擴充以及性能優化都會變得非常友善。使用者使用ByteFUSE和NFS兩種協定通路ByteNAS的流程如下圖所示:

ByteFUSE 的演進與落地

目标

  • 高性能、低延遲,對業務友好的架構模型設計
  • 完全相容Posix語義
  • 支援一寫多讀/多寫多讀
  • 自研以及可維護性強,提供定制化特性能力支援

演進路線

1. ByteFUSE 1.0 — 基礎功能完備,雲原生化部署支援

通過原生FUSE接入ByteNAS

原生FUSE對接ByteNAS的整體架構圖如下所示:

ByteFUSE 的演進與落地
  • ByteFUSE Daemon: 內建了ByteNAS SDK的FUSE Daemon,使用者的檔案系統請求會通過FUSE協定轉發給ByteFUSE Daemon,然後,通過ByteNAS SDK被轉發到後端存儲叢集。

雲原生化部署支援

ByteFUSE基于K8S CSI接口規範 [1] 開發了CSI插件,以支援在K8S叢集中使用ByteFUSE通路ByteNAS叢集,其架構如下圖所示:

ByteFUSE 的演進與落地
  • CSI-Driver: ByteFUSE的雲原生架構目前隻支援靜态卷,Mount/Umount操作會在CSI-Dirver中啟動/銷毀FUSE Client,CSI-Driver會記錄每個挂載點的狀态,當CSI-Drvier異常退出重新開機時會recover所有挂載點來保證高可用性。
  • FUSE Client: 即上面提到的ByteFUSE Daemon,在1.0架構下,針對每個挂載點,CSI-Driver都會啟動一個FUSE Client來提供服務。

2. ByteFUSE 2.0 — 雲原生架構更新,一緻性、可用性和可運維性提升

業務需求和挑戰

  • FUSE Client資源占用不可控以及無法複用

多FUSE Client模式下,一個挂載點對應一個FUSE Client程序,FUSE Client的資源占用與挂載點個數強相關,這導緻FUSE Client資源占用不可控。

  • FUSE Client與CSI-Driver強耦合導緻CSI-Driver無法平滑更新

FUSE Client程序的生命周期與CSI-Driver關聯,當需要更新CSI時,FUSE Client也需要跟随重建,導緻業務I/O也會受影響,同時,這個影響時長與CSI-Driver的更新時長(秒級)強相關。

  • 部分業務希望在Kata容器場景接入ByteFUSE

雲原生場景下,有部分業務會以Kata容器的方式來運作,為了滿足這部分業務接入ByteFUSE的需求,CSI-Driver需要支援kata這種容器運作時,即在kata虛機内能夠通過ByteFUSE通路ByteNAS服務。

  • 原生FUSE一緻性模型無法滿足某些業務需求

某些業務是典型的一寫多讀場景,對讀寫吞吐,資料可見性以及尾延遲的要求極高,但原生FUSE在開啟核心緩存的情況下,無法提供像CTO (Close-to-Open) 這樣的一緻性模型。

  • 原生FUSE可用性/可運維性能力較弱,無法适用于大規模生産環境

原生FUSE對高可用、熱更新等能力的支援較弱,當出現FUSE程序crash或者核心子產品有bug需要更新等情況時,往往需要知會業務重新開機Pod、甚至重新開機整個實體節點,這對于大部分業務都是不可接受的。

雲原生架構更新

FUSE Client架構更新:單Daemon化

針對上述業務需求和挑戰,我們對架構進行了更新,支援了單FUSE Daemon模式來解決資源不可控以及資源無法複用的問題,采用FUSE Daemon和CSI-Driver的分離解決CSI-Driver無法平滑更新的問題,其架構如下圖所示:

ByteFUSE 的演進與落地
  • AdminServer: 監控Mountpoint/FUSE Daemon狀态,更新FUSE Daemon以及統計叢集資訊等。
  • FUSE Daemon: 管理ByteNAS叢集所有的挂載點以及處理讀寫請求,重新開機後recover所有的挂載點,恢複時間為ms級别。

Kata Containers 場景支援

為了提供Kata場景的支援,同時,解決原生FUSE的高可用和性能可擴充性問題,我們在2.0架構中引入了VDUSE[2]這個位元組自主研發的技術架構來實作ByteFUSE Daemon。VDUSE利用了virtio這套成熟的軟體架構,使ByteFUSE Daemon能夠同時支援從虛機或者主控端(容器)挂載。同時,相較于傳統的FUSE架構,基于VDUSE實作的FUSE Daemon不再依賴/dev/fuse這個字元裝置,而是通過共享記憶體機制來和核心通信,這種方式一方面對後續的性能優化大有裨益,另一方面也很好地解決了Crash Recovery問題。

ByteFUSE 的演進與落地

一緻性、可用性和可運維性提升

一緻性模型增強

性能和一緻性是分布式系統設計中的一對根本性沖突 —— 保持一緻性意味着更多節點的通信,而更多節點的通信意味着性能的下降。為了滿足相關業務需求,我們在FUSE原生緩存模式的基礎上不斷的取舍性能與一緻性,實作了 FUSE CTO (Close-to-Open) 一緻性模型 [4],并将這些一緻性模型根據不同配置抽象成以下五種:

ByteFUSE 的演進與落地

Daemon高可用

由于ByteFUSE 2.0架構引入了VDUSE [2]這個技術架構,是以支援使用基于共享記憶體的Virtio協定作為傳輸層,Virtio協定内置的inflight I/O追蹤特性可以将 ByteFUSE 正在處理的請求實時持久化,并在 ByteFUSE 恢複時重新處理未完成請求,這彌補了原生 libfuse 中使用字元裝置 /dev/fuse 作為傳輸層時狀态儲存功能的缺失。基于該inflight I/O 追蹤特性,ByteFUSE 進一步考慮了檔案系統狀态在恢複前後的一緻性和幂等性,實作了使用者無感的崩潰恢複 [3],同時基于崩潰恢複實作了Daeamon的熱更新。

核心子產品熱更新

ByteFUSE 在使用定制化核心子產品來獲得更好的性能、可用性和一緻性的同時,也對這些定制化核心子產品的更新維護提出挑戰。為了解決二進制核心子產品無法随核心更新的問題,我們通過 DKMS 來部署定制化核心子產品,讓核心子產品随核心更新而自動重新編譯部署。為了解決核心子產品自身熱更新的問題,我們通過将核心子產品所導出的符号名或裝置号與版本号綁定的方式實作了同一核心子產品的多版本共存。新的 ByteFUSE 挂載将自動使用新的核心子產品;舊的 ByteFUSE 挂載延續使用舊核心子產品。

ByteFUSE 的演進與落地

目前,通過上述 DKMS 技術及“多版本共存”技術,我們将ByteFUSE核心子產品的更新與核心及ByteFUSE Daemon進行了解耦;未來,我們将進一步實作ByteFUSE核心子產品熱更新功能,以支援線上運作的存量ByteFUSE卷的熱更新功能。

3. ByteFUSE 3.0 — 極緻性能優化,打造業界一流的高性能檔案存儲系統

業務需求和挑戰

  • 大模型訓練場景對存儲系統的性能需求

大模型訓練場景下,訓練巨量模型需要巨大的算力,但随着資料集和模型規模不斷增加,應用程式載入資料所花費的時間變得越長,進而影響了應用程式的性能,緩慢的 I/O 嚴重拖累GPU 的強大算力。于此同時,模型的評估 & 部署需要并行讀取大量模型,要求存儲能夠提供超高吞吐。

  • 雲原生高密部署的場景,需要進一步降低資源占用開銷

雲原生高密部署場景下,随着ByteFUSE卷的數量級增加,對ByteFUSE單機側的資源(CPU & Memory)占用及隔離提出了新的要求。

極緻性能優化

ByteFUSE 3.0從線程模型,資料拷貝,核心側以及協定棧進行了全鍊路的性能優化,性能提高2.5倍,2個core即可打滿百Gb網卡。其優化方向如下所示:

Run-to-Completion線程模型

2.0 版本的一次Read/Write請求會有4次線程切換,接入Run-to-Completion(RTC)能夠節省這四次線程切換帶來的開銷。為了做到Run-to-Completion,我們對ByteFUSE和ByteNAS SDK進行了shared-nothing的設計和鎖的非阻塞化改造,其目的是保證RTC線程不會被阻塞,避免影響請求的延遲。

ByteFUSE 的演進與落地

RDMA & 使用者态協定棧

3.0架構相較于2.0,在網絡傳輸這塊也做了較大的改進,主要展現在引入了RDMA和使用者态協定棧(Tarzan)來替換傳統的核心TCP/IP協定棧,相較于核心TCP/IP協定棧,RDMA/Tarzan能夠節省使用者态與核心态的切換和資料拷貝帶來的延遲,并進一步降低CPU占用。

全鍊路零拷貝

引入RDMA/Tarzan之後,ByteFUSE在網絡傳輸這塊的拷貝被成功消除了,但FUSE接入這塊,仍然存在Page Cache到Bounce Buffer,Bounce Buffer到RDMA/Tarzan DMA Buffer兩次拷貝。為了降低這部分的拷貝開銷(經統計1M資料的拷貝消耗100us左右),3.0架構引入了VDUSE umem [5] 特性,通過将RDMA/Tarzan DMA Buffer注冊給VDUSE核心子產品,減少了其中的一次拷貝。未來,我們還會進一步實作FUSE PageCache Extension特性,來達成全鍊路零拷貝這個優化目标。

ByteFUSE 的演進與落地

FUSE核心優化

多隊列

在原生FUSE/viritofs核心子產品中,FUSE 請求的處理路徑有很多單隊列設計:如每個 FUSE 挂載隻有一個 IQ (input queue)、一個 BGQ (background queue)、virtiofs 裝置使用單隊列模型發送 FUSE 請求等。為了減少單隊列模型帶來的鎖競争、提高可擴充性,我們在 FUSE/virtiofs 的請求路徑中支援了 per-cpu 的 FUSE 請求隊列和可配置的 virtiofs virtqueue 數量。基于 FUSE 多隊列特性的支援,ByteFUSE 可以根據不同部署環境配置不同的 CPU 親和性政策來減少核間通信或平衡核間負載。ByteFUSE 工作線程也可以打開 FUSE 多隊列特性所提供的負載均衡排程來緩解核間請求不均情況下的局部請求排隊現象。

ByteFUSE 的演進與落地

huge塊支援

為了滿足高吞吐場景的性能需求,ByteFUSE 3.0 版本支援定制化的FUSE核心子產品參數。Linux 核心原生的FUSE 子產品中存在一些對資料傳輸的寫死,如單次最大資料傳輸單元為 1 MB,單次最大目錄樹讀取單元為 4 KB。而在ByteFUSE核心子產品中,我們将單次最大資料傳輸上調為 8 MB, 單次最大目錄讀取單元上調為 32 KB。在資料庫備份場景下,将單次寫下刷改成8MB,單機吞吐能提高約20%。

演進收益

收益總覽

1.0 -> 2.0

  • 降低資源占用,便于資源控制

單FUSE Daemon和多FUSE Client相比,多個挂載點之間的線程、記憶體、連接配接等資源可以複用,可以有效降低資源占用。除此之外,将FUSE Daemon單獨運作于Pod内能夠更好地适應Kubernetes生态,保證其在 Kubernetes 的管控内,使用者可以直接在叢集中觀察到FUSE Daemon的Pod,可觀測性強。

  • CSI-Driver與FUSE Daemon解耦合

CSI-Driver與FUSE Daemon作為兩個獨立部署的服務,其部署、更新都可以獨立進行而不影響彼此,進一步降低了運維工作對業務的影響。除此之外,我們支援POD内熱更新FUSE Daemon,整個更新對業務是無感的。

  • 支援核心子產品熱更新

可以在業務無感的情況下,支援對ByteFUSE增量卷進行熱更新,修複核心子產品的已知bug,降低線上風險。

  • 支援統一的監控以及管控平台,友善可視化管理

AdminServer監控一個Region内所有FUSE Daemon & 挂載點的狀态,支援遠端恢複異常挂載點,支援Pod内熱更新FUSE Daemon,支援遠端挂載點異常探測以及報警等。

2.0 -> 3.0

整個架構實作了Run-to-Complete的線程模型,減少了鎖以及上下文切換帶來的性能損耗。除此之外,我們将核心态TCP換成使用者态TCP,bypass核心以及采用記憶體注冊到核心的方式實作全鍊路zero-copy進一步的提升性能。對于1MB的寫請求,FUSE Daemon側可以節省百us。

性能對比

FUSE Daemon 機器規格:

  • CPU: 32實體核,64邏輯核
  • 記憶體:251.27GB
  • NIC: 100Gbps

中繼資料性能對比

使用mdtest進行性能測試,測試指令

mdtest '-d' '/mnt/mdtest/' '-b' '6' '-I' '8' '-z' '4' '-i' '30
           

,性能差異如下所示:

ByteFUSE 的演進與落地

結論

3.0架構相比1.0架構中繼資料性能大約提高了25%左右。

資料性能對比

FIO采用4線程,其性能如下圖所示:

ByteFUSE 的演進與落地

此外,測試ByteFUSE 3.0 polling線程個數對性能的影響。對于寫,2個polling線程基本打滿百G網卡,而對于讀,則需要4個polling線程(比寫操作多一次資料拷貝)。未來,我們将改造使用者态協定棧Tarzan,節省讀的一次資料拷貝,做到讀寫zero-copy。

ByteFUSE 的演進與落地

業務落地

ES存算分離架構場景的落地

場景描述

ES的Shared Storage架構,讓ES 的多個分片副本使用同一份資料,來解決在 Shared Nothing 架構下的擴容生效緩慢,分片遷移慢,搜尋打分振蕩以及存儲成本高等問題。底層存儲使用ByteNAS來共享主副分片的資料以及使用ByteFUSE作為接入協定來滿足高性能,高吞吐以及低延遲的要求。

收益

  • ES存算分離架構的落地,每年節省存儲成本近千萬

AI訓練場景的落地

場景描述

AI 類 Web IDE場景下使用塊存儲 + NFS的方式共享根檔案系統無法解決由于NFS斷聯程序進入D狀态以及NFS斷聯觸發核心Bug導緻mount功能不可用等問題。除此之外,AI訓練場景下受限負載均衡的吞吐以及NFS協定性能的影響無法滿足訓練任務高吞吐 & 低延遲的需求,而ByteNAS提供共享檔案系統,超大吞吐以及低延遲滿足模型訓練。

收益

  • 滿足AI訓練對高吞吐,低延遲的需求

其他業務場景的落地

受限于TTGW吞吐以及穩定性的原因,資料庫備份業務,消息隊列業務,符号表業務以及編譯業務從NFS切換到ByteFUSE。

未來展望

ByteFUSE 3.0架構已經可以滿足絕大部分業務的需求,但是,為了追求更極緻的性能以及滿足更多的業務場景,未來我們還有不少工作有待展開:

  • ByteFUSE推廣到ToB場景;滿足雲上業務超低延遲,超高吞吐的需求
  • 支援非Posix語義;定制化接口滿足上層應用的需求,譬如 IO fencing語意
  • FUSE PageCache Extension;FUSE支援Page Cache使用者态擴充,FUSE Daemon能夠直接讀寫Page Cache
  • 支援核心子產品熱更新;支援使用者無感情況下,更新存量及增量ByteFUSE卷的核心子產品
  • 支援GPU Direct Storage[6];資料直接在RDMA網卡和GPU之間進行傳輸,bypaas主機記憶體和CPU

參考資料

[1] https://kubernetes-csi.github.io/docs/

[2] https://www.redhat.com/en/blog/introducing-vduse-software-defined-datapath-virtio

[3] https://juejin.cn/post/7171280231238467592

[4] https://lore.kernel.org/lkml/[email protected]/

[5] https://lwn.net/Articles/900178/

[6] https://docs.nvidia.com/gpudirect-storage/overview-guide/index.html

更多優秀内容見:https://juejin.cn/user/1838039172387262/posts