移動雲使用 JuiceFS 支援 Apache HBase 增效降本的探索

語言: CN / TW / HK

作者簡介: 陳海峰,移動雲資料庫 Apache HBase 開發人員,對 Apache HBase、RBF、Apache Spark 有濃厚興趣。

背景

Apache HBase 是 Apache Hadoop 生態體系中的大規模、可擴充套件、分散式的資料儲存服務。同時它還是 NoSQL 資料庫。它的設計初衷是為包含了數百萬列的數十億行記錄提供隨機的、強一致性的實時查詢。預設情況下,HBase 的資料會儲存在 HDFS 上,HBase 為 HDFS 做了很多優化來保證穩定性與效能。但是維護 HDFS 本身一點也不輕鬆,要不斷進行監控、運維、調優、擴容、災難恢復等一系列事情,而且在公有云上搭建 HDFS 的費用也是相當高的。為了節省費用、降低維護成本,一些使用者使用 S3(或其他物件儲存)儲存 HBase 的資料。使用 S3 省去了監控運維的麻煩,同時還實現了儲存計算分離,讓 HBase 的擴容縮容都變得更加容易。

然而,HBase 資料接入物件儲存卻不是一件容易的事兒。物件儲存一方面因為自身特性,功能和效能有限,一旦資料被寫入物件儲存後,資料物件即不可改變,另一方面使用檔案系統語義訪問塊儲存有天然侷限性。在使用 Hadoop 原生的 AWS 客戶端來訪問物件儲存時,目錄重新命名操作會遍歷整個目錄下檔案進行拷貝和刪除,效能非常低下。另外重新命名操作也會導致原子性問題,即原本的重新命名操作分解為拷貝和刪除兩個操作,在極端情況下易產生使用者資料檢視不一致情況。類似的還有查詢目錄所有檔案的總大小,原理是通過遍歷迭代依次獲取某個目錄的所有檔案資訊。如果目錄下的子目錄和檔案數量龐大的話,查詢目錄所有檔案總大小複雜度更大,效能更差。

方案選型

經過大量方案調研和社群問題跟蹤,目前雲 HBase 資料接入物件儲存有三種方案。

第一種是 HBase 使用 Hadoop 原生 AWS 客戶端來訪問物件儲存,即 S3AFileSystem。HBase 核心程式碼只需要稍加改動即可使用 S3AFileSystem。這種 HBase 直接對接物件儲存的方案一個需要解決的痛點問題,即目錄的 rename。HBase 在 Hlog 檔案管理、MemStore Flush、表建立、region compaction 和 region split 時都會涉及目錄的 rename。社群對 StoreFIle 進行了優化,解決了一部分的 rename 效能問題。完全解決目錄操作效能問題需要對 HBase 核心原始碼進行大刀闊斧地變動。

第二個方案是引入 Alluxio 作為快取加速,不僅大大提升讀寫效能,而且引入檔案元資料管理,徹底解決了目錄操作效能低下問題。看似圓滿的結局,背後卻有很多限制條件。當 Alluxio 配置僅僅使用記憶體時,對目錄操作耗時才是 ms 級別。如果配置 Alluxio 的 UFS,Alluxio 中的元資料操作有兩個步驟:第一步是修改 Alluxio master 的狀態,第二步是向 UFS 傳送請求。可以看到,元資料操作仍然不是原子的,當操作正在執行或發生任何故障時,其狀態是不可預測的。Alluxio 依賴 UFS 來實現元資料操作,比如重新命名檔案操作會變成複製和刪除操作。HBase 中資料必定是需要落盤的,Alluxio 解決不了目錄操作效能問題。

第三種方案是在 HBase 與物件儲存之間引入 JuiceFS 共享檔案系統。使用 JuiceFS 儲存資料,資料本身會被持久化在物件儲存(例如,移動雲 EOS),相對應的元資料可以按需持久化在 Redis、MySQL 等多種資料庫中。此方案中對目錄操作完成是在 Metadata Engine 中完成,與物件儲存無互動,操作耗時在 ms 級別,可以解決 HBase 資料接入物件儲存的痛點問題。但是由於 JuiceFS 核心採用 Go 語言編寫,對後期效能調優和日常維護帶來一定挑戰。

權衡上述三個方案利弊,最終採用 JuiceFS 作為雲 HBase 支援物件儲存的解決方案。下面著重討論 JuiceFS 在雲 HBase 支援物件儲存中的實踐以及效能調優。

方案介紹

首先介紹下 JuiceFS 的架構。JuiceFS 由兩個主要部分組成:JuiceFS 元資料(Metadata)服務和物件儲存。JuiceFS Java SDK 完全相容 HDFS API,同時也提供基於 FUSE 的客戶端掛載,完全相容 POSIX。作為檔案系統,JuiceFS 會分別處理資料及其對應的元資料,資料會被儲存在物件儲存中,元資料會被儲存在元資料引擎中。在資料儲存方面,JuiceFS 支援幾乎所有的公有云物件儲存,同時也支援 OpenStack Swift、Ceph、MinIO 等支援私有化部署的開源物件儲存。在元資料儲存方面,JuiceFS 採用多引擎設計,目前已支援 Redis、TiKV、MySQL/MariaDB、PostgreSQL、SQLite 等作為元資料服務引擎。

任何存入 JuiceFS 的檔案都會被拆分成固定大小的 "Chunk",預設的容量上限是 64 MiB。每個 Chunk 由一個或多個 "Slice" 組成,Slice 的長度不固定,取決於檔案寫入的方式。每個 Slice 又會被進一步拆分成固定大小的 "Block",預設為 4 MiB。最後,這些 Block 會被儲存到物件儲存。與此同時,JuiceFS 會將每個檔案以及它的 Chunks、Slices、Blocks 等元資料資訊儲存在元資料引擎中。

使用 JuiceFS,檔案最終會被拆分成 Chunks、Slices 和 Blocks 儲存在物件儲存。因此,物件儲存平臺中找不到存入 JuiceFS 的原始檔,儲存桶中只有一個 chunks 目錄和一堆數字編號的目錄和檔案。

HBase 元件使用 JuiceFS 需要以下配置。首先將編譯好的客戶端 SDK 置於 HBase classpath 內。其次將 JuiceFS 相關配置寫入配置檔案 core-site.xml,如下表所示。最後使用 juicefs 客戶端格式化檔案系統。

配置項 預設值 描述
fs.jfs.impl io.juicefs.JuiceFileSystem 指定要使用的儲存實現,預設使用 jfs://
fs.AbstractFileSystem.jfs.impl io.juicefs.JuiceFS
juicefs.meta 指定預先建立好的 JuiceFS 檔案系統的元資料引擎地址。

在元資料儲存方面,使用 MySQL 作為元資料儲存。格式化檔案系統命令如下。可見,格式化檔案系統需要提供以下資訊:

  • --storage:設定儲存型別,比如移動雲 EOS;
  • --bucket:設定物件儲存的 Endpoint 地址;
  • --access-key:設定物件儲存 API 訪問金鑰 Access Key ID;
  • --secret-key:設定物件儲存 API 訪問金鑰 Access Key Secret。
juicefs format --storage eos \
--bucket https://myjfs.eos-wuxi-1.cmecloud.cn \
--access-key ABCDEFGHIJKLMNopqXYZ \
--secret-key ZYXwvutsrqpoNMLkJiHgfeDCBA \
mysql://username:[email protected](ip:port)/database NAME

方案驗證與優化

介紹完 Juicefs 使用方法後,開始進行測試工作。測試環境中選用了一臺 48 核、187G 記憶體的伺服器。在 HBase 叢集中,分別有一個 HMaster、一個 RegionServer 和三個 zookeeper。在 Meta data engine 選用主從複製的三節點 MySQL。物件儲存則使用移動雲物件儲存 EOS,網路策略走公網。Juicefs 配置 chunk 大小為 64M,物理儲存塊大小為 4M,無 cache,MEM 使用 300M。我們搭建了兩套 HBase 叢集,一套是 HBase 直接落盤到移動雲物件儲存上,另一套是在 HBase 和移動雲物件儲存之間引入 Juicefs。順序寫和隨機讀是 HBase 叢集兩個關鍵效能指標,使用 PE 測試工具測試這兩個效能指標。測試讀寫效能如下表所示。

叢集環境

叢集環境 HBase-juicefs-EOS (row/s) 叢集環境 HBase-EOS (row/s)
順序寫 79465 33343
隨機讀 6698 6476

根據測試結果,採用 Juicefs 方案,叢集順序寫效能提升非常明顯,隨機讀效能卻沒有提升。究其原因,寫請求寫入 Client 記憶體緩衝區即可返回,因此通常來說 JuiceFS 的 Write 時延非常低(幾十微秒級別)。JuiceFS 在處理讀請求時,一般會按照 4M Block 對齊的方式去物件儲存讀取,實現一定的預讀功能,同時,讀取到的資料會寫入本地 Cache 目錄,以備後用。在順序讀時,這些提前獲取的資料都會被後續的請求訪問到,Cache 命中率非常高,因此也能充分發揮出物件儲存的讀取效能。但是在隨機讀取時,JuiceFS 的預先快取效率不高,反而會因為讀放大和本地 Cache 的頻繁寫入與驅逐使得系統資源的實際利用率降低。

為了提升隨機讀效能,兩個方向可以考慮。一個是儘可能提升快取的整體容量,以期達到能幾乎完全快取所需資料的效果,在海量資料的使用場景下,這個優化方向不太可行。另一個方向是深耕 JuiceFS 核心,優化讀資料邏輯。

目前我們所做的優化包括:1)關閉預讀機制和快取功能,簡化讀資料邏輯;2)儘可能避免快取整個塊資料,更多地使用 Range HTTP 請求資料;3)設定較小的 block 大小;4)儘可能提高物件儲存的讀取效能。經研發環境測試,經優化後隨機讀效能提升大約 70%。

結合前期測試工作,雲 HBase 在使用物件儲存作為底層資料儲存系統後,在獲得與資料儲存在 HDFS 差不多讀寫效能基礎上,使用者花費卻只有資料儲存在 HDFS 的一半以下,由此可以看出雲 HBase 支援物件儲存是魚與熊掌兼得的一次研發實踐。

如有幫助的話歡迎關注我們專案 Juicedata/JuiceFS 喲! (0ᴗ0✿)