JuiceFS 如何幫助趣頭條超大規模 HDFS 降負載

  • 2021 年 10 月 26 日
  • 筆記

作者簡介

  • 王振華,趣頭條大數據總監,趣頭條大數據負責人。
  • 王海勝,趣頭條大數據工程師,10 年互聯網工作經驗,曾在 eBay、唯品會等公司從事大數據開發相關工作,有豐富的大數據落地經驗。
  • 高昌健,Juicedata 解決方案架構師,十年互聯網行業從業經歷,曾在知乎、即刻、小紅書多個團隊擔任架構師職位,專註於分散式系統、大數據、AI 領域的技術研究。

背景

趣頭條大數據平台目前有一個近千節點的 HDFS 集群,承載著存儲最近幾個月熱數據的功能,每日新增數據達到了百 TB 規模。日常的 ETL 和 ad-hoc 任務都會依賴這個 HDFS 集群,導致集群負載持續攀升。特別是 ad-hoc 任務,因為趣頭條的業務模式需要頻繁查詢最新的數據,每天大量的 ad-hoc 查詢請求進一步加重了 HDFS 集群的壓力,也影響了 ad-hoc 查詢的性能,長尾現象明顯。集群負載高居不下,對很多業務組件的穩定性也造成了影響,如 Flink 任務 checkpoint 失敗、Spark 任務 executor 丟失等。

因此需要一種方案使得 ad-hoc 查詢盡量不依賴 HDFS 集群的數據,一方面可以降低 HDFS 集群的整體壓力,保障日常 ETL 任務的穩定性,另一方面也能減少 ad-hoc 查詢耗時的波動,優化長尾現象。

方案設計

趣頭條的 ad-hoc 查詢主要依靠 Presto 計算引擎,JuiceFS 的 Hadoop SDK 可以無縫集成到 Presto 中,無需改動任何程式碼,以不侵入業務的方式自動分析每一個查詢,將需要頻繁讀取的數據自動從 HDFS 拷貝至 JuiceFS,後續的 ad-hoc 查詢就可以直接獲取 JuiceFS 上已有的快取數據,避免對 HDFS 產生請求,從而降低 HDFS 集群壓力。

另外由於 Presto 集群是部署在 Kubernetes 上,有彈性伸縮集群的需求,因此需要能夠將快取數據持久化。如果使用獨立的 HDFS 或者某些快取方案的話,成本會很高,此時 OSS 成為最理想的選擇。

整體方案設計如下圖所示。綠色部分表示 JuiceFS 的組件,主要包含兩部分:JuiceFS 元數據服務(下圖中的 JuiceFS Cluster)及 JuiceFS Hadoop SDK(下圖與 Presto worker 關聯的組件)。

JuiceFS 元數據服務用於管理文件系統中所有文件的元資訊,如文件名、目錄結構、文件大小、修改時間等。元數據服務是一個分散式集群,基於 Raft 一致性協議,保證元數據強一致性的同時,還能確保集群的可用性。

JuiceFS Hadoop SDK(以下簡稱 SDK)是一個客戶端庫,可以無縫集成到所有 Hadoop 生態組件中,這裡的方案即是集成到 Presto worker 中。SDK 支援多種使用模式,既可以替代 HDFS 將 JuiceFS 作為大數據平台的底層存儲,也可以作為 HDFS 的快取系統。這個方案使用的便是後一種模式,SDK 支援在不改動 Hive Metastore 的前提下,將 HDFS 中的數據透明快取到 JuiceFS 中,ad-hoc 查詢的數據如果命中快取將不再需要請求 HDFS。同時 SDK 還能保證 HDFS 與 JuiceFS 間數據的一致性,也就是說當 HDFS 中的數據發生變更時,JuiceFS 這邊的快取數據也能同步更新,不會對業務造成影響。這是通過比較 HDFS 與 JuiceFS 中文件的修改時間(mtime)來實現的,因為 JuiceFS 實現了完整的文件系統功能,所以文件具有 mtime 這個屬性,通過比較 mtime 保證了快取數據的一致性。

為了防止快取佔用過多空間,需要定期清理快取數據,JuiceFS 支援根據文件的訪問時間(atime)來清理 N 天前的數據,之所以選擇用 atime 是為了確保那些經常被訪問的數據不會被誤刪除。需要注意的是,很多文件系統為了保證性能都不會實時更新 atime,例如 HDFS 是通過設置 dfs.namenode.accesstime.precision 來控制更新 atime 的時間間隔,默認是最快 1 小時更新 1 次。快取的建立也有一定的規則,會結合文件的 atime、mtime 和大小這些屬性來決定是否快取,避免快取一些不必要的數據。

測試方案

為了驗證以上方案的整體效果,包括但不限於穩定性、性能、HDFS 集群的負載等,我們將測試流程分為了多個階段,每個階段負責收集及驗證不同的指標,不同階段之間可能也會進行數據的橫向比較。

測試結果

HDFS 集群負載

我們設計了兩個階段分別開啟和關閉 JuiceFS 的功能。在開啟階段隨機選取 10 台 HDFS DataNode,統計這一階段每台 DataNode 平均每天的磁碟讀 I/O 吞吐,平均值約為 3.5TB。在關閉階段同樣選擇這 10 個節點,統計下來的平均值約為 4.8TB。因此使用 JuiceFS 以後可以降低 HDFS 集群約 26% 的負載,如下圖所示。

從另一個維度也能反映 HDFS 集群負載降低的效果,在這兩個階段我們都統計了讀取及寫入 JuiceFS 的 I/O 總量。JuiceFS 的讀 I/O 表示為 HDFS 集群降低的 I/O 量,如果沒有使用 JuiceFS 那麼這些請求將會直接查詢 HDFS。JuiceFS 的寫 I/O 表示從 HDFS 拷貝的數據量,這些請求會增大 HDFS 的壓力。讀 I/O 總量應該越大越好,而寫 I/O 總量越小越好。下圖展示了某幾天的讀寫 I/O 總量,可以看到讀 I/O 基本是寫 I/O 的 10 倍以上,也就是說 JuiceFS 數據的命中率在 90% 以上,即超過 90% 的 ad-hoc 查詢都不需要請求 HDFS

平均查詢耗時

在某一階段將各 50% 流量的查詢請求分配給未對接和已對接 JuiceFS 的兩個集群,並分別統計平均查詢耗時。從下圖可以看到,使用 JuiceFS 以後平均查詢耗時降低約 13%

測試總結

JuiceFS 的方案在不改動業務配置的前提下,以對業務透明的方式大幅降低了 HDFS 集群的負載,超過 90% 的 Presto 查詢不再需要請求 HDFS,同時還降低了 13% 的 Presto 平均查詢耗時,超出最初設定的測試目標預期。之前長期存在的大數據組件不穩定的問題也得到解決。

值得注意的是,整個測試流程也很順暢,JuiceFS 僅用數天就完成了測試環境的基礎功能和性能驗證,很快進入到生產環境灰度測試階段。在生產環境中 JuiceFS 的運行也非常平穩,承受住了全量請求的壓力,過程中遇到的一些問題都能很快得到修復。

未來展望

展望未來還有更多值得嘗試和優化的地方:

  • 進一步提升 JuiceFS 快取數據的命中率,降低 HDFS 集群負載。
  • 增大 Presto worker 本地快取盤的空間,提升本地快取的命中率,優化長尾問題。
  • Spark 集群接入 JuiceFS,覆蓋更多 ad-hoc 查詢場景。
  • 將 HDFS 平滑遷移至 JuiceFS,完全實現存儲和計算分離,降低運維成本,提升資源利用率。

項目地址
Github (//github.com/juicedata/juicefs)如有幫助的話歡迎 star (0ᴗ0✿),鼓勵鼓勵我們喲!