今天,高效能運算結合人工智慧技術正在推動科研創新。例如通過破解水稻基因密碼推動作物育種從「試驗選優」向「計算選優」發展,在醫藥領域快速分析分子與蛋白之間的相互作用,發現潛在的能夠有效干預疾病發生的藥物分子。
之江實驗室就是上述科研創新的推動者,實驗室由浙江省政府主導、浙江大學等院校支援、企業參與的事業單位性質的新型研發機構,為材料、基因、製藥、天文、育種等科學領域的研究提供新的方法、工具和手段。
由於算力資源的天然異構性,以及不同技術實現的計算能力往往出自不同的系統架構或指令集,會導致軟體不相容性,從而提高了算力使用的門檻,也使得算力利用率難以有效提高。為解決這個問題,之江實驗室將各種異構算力資源匯聚在一起,形成一個龐大的「算力池」。本文將分享之江實驗室如何基於 JuiceFS 為超異構算力叢集構建儲存層的實踐。
數位反應堆是之江實驗室一個大型科研裝置。整個科研裝置由軟硬體部分組成。在軟體方面,負責研發之江瑤光智慧作業系統。
該智慧作業系統主要包含兩個關鍵組成部分。首先,它提供了通用的計算平臺解決方案,為上層應用層提供支援。通過這個平臺,使用者可以針對不同的應用領域,如計算材料、計算製藥、計算天文等,進行開發和應用。
其次,我們實現了一個異構資源聚合方案。在之江實驗室,我們擁有多個異構叢集,包括CPU叢集、GPU叢集以及一些超算資源。這些不同型別的計算資源具有不同的使用方式。通過異構資源聚合方案,我們將這些不同的計算資源統一聚合,實現統一的管理和使用。
整體架構如上,在之江實驗室的計算與資料中心,我們部署了多套異構叢集,包括 H3C 的傲飛叢集、之江的計算叢集、國產的曙光叢集等,以及邊緣計算場景,這些都納入了我們的管控系統中。通過叢集裝置外掛的方式,我們對這些不同的叢集進行了統一抽象,並實現了算力的聚合。在整個異構算力聯邦的體系中,我們將這些不同的算力叢集都抽象為 Kubernetes(k8s)叢集進行管理。
上層下發的業務指令及不同型別的作業,通過元排程器來決定將這些作業傳送到哪個叢集。根據不同的排程策略,如計算優先順序、能耗優先順序和效能優先順序,來確定計算作業的具體執行方式。目前,我們已接入約 200P(PFLOPS, 1P 相當於每秒執行一千萬億次浮點運算) 的 AI 算力和 7000 核的 HPC 算力。
首先:儲存層的抽象和統一。因為在許多計算場景中,包括超算和AI訓練,都使用 POSIX 介面。因此,我們希望在這一層面上統一使用 JuiceFS 的介面來提供服務。
第二個方面:儲存方案的通用性。目前接入的算力叢集是異構的,那麼儘量需要考慮方案在不同的異構叢集中都能適用。
第三個方面:資料的編排條件。我們的資料是有典型的冷熱特性,在一個任務在計算過程中,它用到的資料是熱資料,任務計算之後或者過了幾天之後,這個資料就變成了冷資料,我們對冷資料的讀和操作是比較少的。
第四個方面:儲存效能的要求。資料讀寫效能要好。特別是熱資料的讀取效能。在算力叢集中,計算資源非常寶貴,如果因為資料讀取慢導致CPU,GPU空轉等待,是極大的浪費。
方案1:裸露的物件儲存(OSS)與S3FS + NAS 相結合
這個方案存在一個較大的問題,即直接使用裸露的物件儲存效能非常差。另外,裸露使用物件儲存的 S3FS 掛載點經常會出現莫名其妙的丟失。一旦掛載點丟失,容器將無法存取,如果要恢復掛載點,必須對整個容器進行重啟,這對使用者業務造成了很大的干擾。
由於開始時叢集規模較小,而且這套方案部署簡單,實驗室一開始採用了這種方案進行部署。但隨著叢集規模的逐漸擴大,尤其是從去年開始建設的數位反應堆,從單一叢集到多叢集的演進過程中,當節點數量從最初的 10 多臺逐漸擴充套件到 100 多個節點時,這個方案基本上已經行不通了。
方案2:Alluxio + Fluid + OSS
經過調研,我們發現該方案的結構相對複雜,涉及到許多元件的組成。之江實驗室是一個超異構的多叢集環境,由於 Alluxio 並不是一個強一致性的檔案系統,它實際上只是一個快取的粘合層。在這種多叢集環境下,會面臨後設資料不一致的問題,而解決這個問題特別困難。由於上層使用者的業務產品非常繁多,我們不能干涉使用者的使用方式。在這種情況下,如果不同叢集之間的資料不一致,將會導致嚴重的問題。其次底層仍然使用OSS,當資料規模擴大到一定程度時,由於 OSS 的後設資料效能問題,當儲存規模達到一定級別後, 後設資料同步、新叢集的快取層初始化等操作也會遇到較大的效能瓶頸。
方案3 :JuiceFS(最終採用)
JuiceFS 有非常詳細的社群檔案,可以直接上手使用,並且在我們的搭建測試叢集以及最終的上線部署中表現出色。另外,JuiceFS 支援 CSI可以容器化部署,另外對國產硬體的適配性較好。因此我們最終選擇將 JuiceFS 作為我們算力側的儲存底座。
首先,JuiceFS 提供了豐富的後設資料引擎選擇,比如 Redis 和 TiKV,使得 JuiceFS 具有較好的後設資料效能。目前我們實驗室使用的是由三個節點搭建的 TiKV 作為後設資料引擎。由於該設定是去年建立的,現在的效能已經有些不夠用,後續我們將逐步提升效能。
最初我們考慮使用 Redis 作為後設資料引擎,但後來發現如果使用 Redis,就無法實現水平擴容。從而使用了 TiKV,則可以隨著檔案系統數量的增長逐步擴充套件,這確實更好。
第二,在跨叢集環境下,使用 JuiceFS 可以實現檔案的原子性和一致性。在叢集 A 中寫入的檔案在叢集 B 中立即可見。然而,如果使用 Alluxio,就無法做到這一點。Alluxio 需要進行一些資料同步事件等操作才能實現,而這些事件實際上會帶來一定的開銷。
第三, JuiceFS 具備快取能力。使用者端可以設定一個快取目錄,使用快取後可以大大降低算力叢集對底層儲存的壓力。
第四,JuiceFS 對於 POSIX 的相容性非常好。我們發現 Alluxio 的實際相容性並不那麼好,而且其使用者端效能相對較一般。Alluxio 可能更適用於不同異構資料來源的統一接入層,用於讀取資料較好。但是,如果需要頻繁寫入或修改資料,則可能使用起來並不理想。
第五 JuiceFS 的社群是常活躍。
這個是我們自己在實驗室環境下測出來的,測試工具:FIO 16 執行緒、4M Block 、1GB 資料 上圖 NAS 的效能就沒法看,因為當時測評的時候還在生產環境正在提供服務,當時有大概七十幾個節點正在執行,頻寬很小,基本就執行不了。
初期,整個高效能運算的過程實際上是分為很多個環節,但是資料分散在不同的儲存系統中會帶來使用效率和便利性上的挑戰。為了簡化資料的管理和流轉,我們使用了一個統一的儲存底座作為儲存基礎設施。儲存底座的核心能力包括高可靠性、低成本和高吞吐量,因此我們選擇了物件儲存作為儲存底座。將資料儲存到物件儲存中可以輕鬆實現資料的冷熱分層,從而節省儲存空間。
然而,直接讓計算叢集直接使用裸物件儲存仍然存在一些問題。首先是後設資料效能差的問題,例如對同一目錄下檔案的列表操作,在檔案數量較多的情況下,耗時會非常長。第二個問題是頻寬消耗大,資料湖提供的是普通的IP網路,而不是 RDMA 高速網路,因此總頻寬有限。
因此,在物件儲存之外,我們還建立了一個後設資料叢集,並使用了 TiKV 資料庫。基於物件儲存和 TiKV,我們構建了JuiceFS 分散式檔案系統。算力叢集通過在節點上安裝 JuiceFS 使用者端來讀取檔案系統的資料。這樣,我們可以克服物件儲存的一些限制,提高後設資料效能,並減少頻寬消耗。
為了實現高效的資料流轉,我們通過檔案管理系統允許使用者進行檔案的上傳和下載操作。檔案管理系統底層採用JuiceFS S3 閘道器,將資料寫入底層儲存。
除了資料湖和後設資料叢集,我們還建立了一個快取記憶體叢集,它緊密部署在計算叢集中,主要目的是為了實現最佳的 I/O 效能。這樣解決了計算叢集與物件儲存資料湖底座之間高效資料流轉的問題。使用者並不需要關心資料是儲存在物件儲存中還是在快取記憶體叢集中。
算力系統對資料流轉進行管控。計算叢集和快取記憶體叢集之間通過200G的RDMA高速網路連線。快取記憶體叢集上部署了BeeGFS高速並行檔案系統,將該檔案系統作為一個目錄掛載到計算叢集。這樣,計算叢集可以像使用本地目錄一樣使用該快取系統。
在不同的業務場景中,對儲存的需求和效能指標是不一樣的。為了能夠更高效地服務使用者,我們提出了打造儲存能力產品化這樣的想法,目前JuieFS 被應用到了以下幾類儲存產品中。
JuiceFS 會將其資料儲存在一個特定的目錄下,並根據使用者所屬的組織架構生成一個唯一的存取路徑。通過直接將該路徑掛載到容器內,實現資料的隔離。使用者可以通過頁面端進行檔案的上傳和下載,也可以使用我們提供的命令和工具對檔案進行操作。
在初始建設階段,通用檔案儲存存在一個問題,容量的擴充套件性較差。底層的物件儲存叢集(oss)的容量有限,隨著資料量的增加,使用者無法申請更多的儲存空間。為解決這個問題,我們引入了儲存卷的概念。
儲存卷可以類比為雲盤,不同的儲存卷相當於不同型別的雲盤。對於不同的儲存型別,我們可以將它們包裝成不同的儲存卷,以滿足使用者在不同場景下的需求。
對於需要頻繁地讀寫海量小檔案的場景,它需要使用延遲較低且吞吐量較高的儲存產品。為滿足這種需求,我們將之前搭建的快取記憶體叢集轉化為高速儲存卷的功能,直接將其檔案系統目錄開放給使用者使用。這樣,使用者可以直接使用高速儲存,而無需通過 JuiceFS 來存取,可以更直接地感受到高速儲存的效能優勢。
而對於需要儲存巨量資料但實際上不頻繁讀取的使用者,可以結合JuiceFS和物件儲存來建立標準儲存卷。這樣可以提供較大的儲存容量和可接受的吞吐效能,同時相對於高速儲存卷,支援跨叢集的網路互通能力。
此外,一些使用者可能對效能有更高的要求,例如他們需要本地盤的產品,但同時也需要資料持久化的能力。在 Kubernetes 場景下,如果使用者直接將資料寫入本地盤,存在資料丟失的風險,例如遇到意外重啟或物理節點問題。在這種情況下,使用者需要一種持久化的解決方案。我們可以通過將使用者在受影響節點的本地盤開放一部分儲存空間作為本地儲存卷,並在作業排程時根據使用者指定的儲存卷將任務排程到指定的節點上。
另外,不同儲存產品在容量、吞吐量和跨叢集互通能力方面存在差異。例如,高速儲存可以在叢集內部進行互通,但無法跨叢集;儲存產品的容量和成本也各不相同。高速儲存採用全快閃記憶體的叢集,建設成本較高,而物件儲存的建設成本相對較低,且具備較大的儲存容量。因此,將不同的儲存硬體(設施)能力包裝成不同的儲存產品來適配使用者不同的業務場景。
在使用 JuiceFS 時,我們還實現了一個資料編排功能。管理員可以將常用的資料集上傳到檔案系統某個目錄,這個目錄可以在上層抽象成一個公開的資料集。不同使用者在建立作業時都可以掛載這些資料集。普通使用者也可以上傳自己的私有資料集,並通過 JuiceFS 的預熱功能對這些資料集進行預熱。
我們在算力叢集內部建立了一個快取記憶體叢集。使用 warmup 指令,使用者的資料集可以直接從兩端預熱到計算節點的快取記憶體叢集。這樣,使用者在進行大量模型訓練時,可以直接與自己搭建的高效能叢集互動,無需與遠端 OSS 叢集進行互動,從而獲得更好的效能。
另外,這種設定可以降低物件儲存底座的網路頻寬壓力。整個快取的淘汰過程由 JuiceFS 使用者端自動管理,因為可以對存取目錄進行上限容量的設定。對使用者來說,這部分功能相對透明且易於使用。
在我們選擇使用JuiceFS之後,我們在內部進行了一些檔案讀取效能的測試,並與演演算法團隊合作進行了測試。當時,從測試結果看,JuiceFS 的讀取效能總是比 NAS 慢得多。我們開始查詢原因為什麼 JuiceFS 比 NAS 還要慢。
後來我們發現,在使用 JuiceFS 和 TiKV 作為後設資料的場景中,像列舉目錄這樣的 API 操作實際上是隨機的,它並不像 NAS 或其他檔案系統那樣保證一致的順序。在這種情況下,如果演演算法是基於隨機選擇檔案或者程式碼是固定的,那麼可能會認為選擇的那些檔案應該是固定的。
在處理海量小檔案的場景中,後設資料的開銷是相當可觀的。如果後設資料沒有被快取到記憶體中,每次都需要從後設資料引擎那裡獲取,與沒有快取相比這會帶來較大的開銷。因此,通過這個問題,我們發現在特定的場景下需要對檔案的索引目錄進行編排。例如,某個演演算法可能需要處理數十萬甚至數百萬個檔案,如果要確保演演算法訓練的一致性,首先需要將這些檔案作為索引檔案,作為自己的一個索引目錄樹。每次進行演演算法訓練時,直接讀取索引檔案,而不再呼叫 list dir 的操作,以確保這個資料夾下的檔案目錄樹在演演算法訓練中保持一致性。
編著注:
造成讀效能慢主要與使用者的使用場景相關,評估後對「目錄的隨機讀」這個功能未作調整,如果其他使用者在這個問題上也有類似問題,歡迎提出。
在使用過程中,我們遇到了 TiKV 無法進行垃圾回收的問題。由於我們只使用了這個檔案系統,並且顯示容量為 106T、1.4 億個檔案,而 TiKV 佔用了 2.4T 的容量,這顯然是不正常的。
根據官方檔案的顯示,例如 Redis,大約 1 億個檔案應該只佔用大約 30GB 的容量。我們進行了排查後發現可能是 TiKV 的後設資料引擎沒有進行垃圾回收。我們還檢視了報表,發現整個垃圾回收指標為空。可能的原因是我們只部署了 TiKV,而沒有部署 TiDB。然而,TiKV 的垃圾回收實際上需要依賴 TiDB,這是一個容易被忽視的問題點。
編著注:
JuiceFS 在 #3262 和 #3432 的 PR 中加上了 TiKV 的後臺 GC 任務,修復了這個問題。這些修復已經在 v1.0.4 中合入。
當我們掛載 JuiceFS 使用者端時,我們將快取記憶體叢集設定為儲存目錄,並將其容量設定得相對較高,理論上限為 50T。
在這種情況下,JuiceFS 使用者端會定期掃描快取目錄,並建立記憶體索引,以便 JuiceFS 知道哪些資料位於快取目錄中。因此,這會佔用相當多的記憶體。如果目錄非常龐大,我們建議使用者關閉這個掃描功能。
在測試小檔案隨機 I/O 時,我們覺得表現還可以,但在測試順序 I/O 時,出現了一個較大的問題。例如,使用 dd 命令建立一個 500MB 的檔案,結果發現物件儲存生成了大量快照。可以看出,這裡的儲存和對物件儲存的操作遠遠超過了建立一個 500MB 檔案應有的操作。
在進一步排查時,我們發現在啟用 -o writeback_cache
引數後,順序寫會變成隨機寫,從而降低整體的順序寫效能。該引數只適用於非常高階的隨機性場景。如果在不是這種場景下使用該引數,將導致嚴重的問題。這也是在使用 JuiceFS 時需要注意的一個點。
編著注:
這個問題主要是針對使用 NAS 做快取的場景,已經在1.1beta中優化,掃描時大幅減少記憶體佔用,並提升速度。JuiceFS 在 #2692 中新增了--cache-scan-interval
來自定義掃描時間,並且可以選擇只在啟動時掃描一次或完全關閉掃描,使用者可以設定該選項。對於使用本地盤做快取的使用者則不需要調整。
多層次
我們將提供更多層次的軟硬體產品,並將這些能力以不同的儲存卷形式進行產品化,以適應使用者在不同場景下的儲存需求。
隔離性
目前存在資料安全風險,所有使用者的資料都儲存在同一個大型檔案系統中並通過hostpath掛載在裸機。如某些使用者擁有節點登入許可權,實際上可以存取整個檔案系統內部的資料。為了解決這個問題,我們計劃在後續採用 CSI 模式結合路徑客製化來避免隔離性問題。
我們還將上線配額管理功能。在使用者使用儲存產品時,需要有一種強制手段來限制使用者可以使用的儲存容量,並且能夠準確檢視使用者實際使用了多少容量。直接使用 du 命令檢視容量的過程開銷很大,並且不太方便。配額管理功能將解決這個問題。
在計量計費場景下,我們需要了解使用者產生的流量和消耗的能量,並根據實際使用的容量進行計費。因此,良好的容量管理能力是必需的。
監控&運維
在使用 JuiceFS 時,我們是直接在物理機上掛載,通過暴露一個監控埠,我們的生產叢集可以與這些埠進行通訊,並建立了一套監控系統,可以監控和收集所有的監控資料。
資料的容災和遷移能力目前還比較欠缺。我們遇到了一個典型場景,即現有叢集的容量不足,需要上線新的叢集。在新舊叢集之間,如何處理資料遷移以及不同資料的遷移方式,如何在不影響生產使用者的情況下儘量保證業務不中斷,實現資料遷移仍然是一個較為困難的問題。因此,我們計劃在後續尋找解決方案,以提升這方面的能力
另外,我們還在開發基於 JuiceFS 和 CSI 外掛的通用能力,以實現在不同的儲存使用者端上動態掛載的能力。在生產環境中,使用者對掛載引數的調整有一定需求,因為不同的掛載引數適配不同的業務產品。然而,如果直接調整掛載引數,可能會導致整個物理節點的中斷。因此,如果能夠實現動態掛載的能力,使用者只需要對業務進行適當的切換,而無需進行重啟等操作。
對 JuiceFS 一些功能期望:
卷管理能力 (配額、使用者、許可權)卷能力在之前已經部分實現了配額的功能,但實際上我們更需要的是基於使用者和管理人員許可權的管理能力。目前,JuiceFS是掛載在一個大型檔案系統上,如果為每個使用者建立檔案系統,將會帶來很高的開銷。因此,我們目前採用的是基於一個大型檔案系統,通過不同的目錄來管理不同使用者的許可權配合,缺少一個統一的、中心化的使用者許可權管理系統,仍然需要依賴Linux的許可權管理。然而,Linux的許可權管理是分佈在不同節點上的,對使用者許可權的管理相對較為困難。我在思考是否可以依賴後設資料,並將其作為一箇中心化資料庫的能力,實現使用者和許可權的管理。這樣,卷的管理能力就可以更加產品化。
支援分散式快取能力。它可以充分利用計算機的物理資源和本地磁碟,通過叢集內的計算節點和網路進行利用。目前我們瞭解到,商業版有提供這個功能,但社群版也還沒有。
掛載點熱更新能力。在不同的場景下,使用者需要不同的掛載引數,但是解除安裝和重新掛載的操作太重,會影響使用者的業務。使用者可以接受短暫的不可讀取或者讀取中斷,但是不能重啟業務容器或中斷演演算法或策劃程式。我們正在內部調研和開發這個能力。
編著注:
目錄配額需求在1.1Beta中已經實現了,詳情請大家關注下週的發版資訊。分散式快取和掛載點更新能力,目前商業版可以提供,這兩個功能也在社群版的規劃當中。
如有幫助的話歡迎關注我們專案 Juicedata/JuiceFS 喲! (0ᴗ0✿)