JuiceFS 在攜程海量冷資料場景下的實踐

語言: CN / TW / HK

作者|妙成,攜程雲原生研發工程師,主要從事Elasticsearch、JuiceFS的研發運維,關注分散式資料庫、NoSQL。小峰, 攜程雲原生研發工程師,主要專注於資料庫容器化領域,對分散式儲存有濃厚興趣。

一、摘要

攜程的冷資料規模在 10PB+,包括備份資料、圖片語音訓練資料和日誌資料等,儲存方案主要是本地磁碟和GlusterFS。在實際使用中這些方案遇到了不少痛點:

  • GlusterFS 在單目錄下檔案眾多時,ls命令速度很慢;
  • 受疫情期間機器採購週期的制約,無法靈活地根據實際需求彈性擴縮容,儲存成本控制困難;
  • 磁碟損壞等故障帶來的機器替換和擴縮容操作,使得運維成本居高不下。

隨著雲端計算技術的發展,公有云廠商為混合雲客戶提供了海量冷資料的廉價儲存方案,經過嚴謹的成本計算,我們發現使用公有云的物件儲存可以顯著降低儲存和運維成本。為了減少遷移成本,我們一直在尋找後端儲存能支援各類公有云物件儲存、高效能的檔案系統,直到JuiceFS 出現在我們的視野中。JuiceFS有以下優勢:

  • POSIX 介面,對應用無侵入
  • 強一致性,檔案修改立刻可見,為同一個 volume 被多臺機器掛載的場景提供 了close-to-open 保證
  • 支援了主流的公有云物件儲存,支援開源軟體作為元資料引擎(Redis、TiKV)等
  • 支援雲原生,能夠將volume以 CSI 的方式掛載到Pod上
  • 社群活躍,程式碼更新快

經過大半年的測試和使用,我們已經對接了資料庫備份和 ElasticSearch 冷資料儲存,將2PB+的資料遷移到了JuiceFS,預計後續還會有10PB+的資料接入。目前JuiceFS系統穩定,在降低運維成本和儲存成本方面取得了良好的效果。本文將對JuiceFS原理以及我們在使用中所遇到的問題和採取的優化方案進行簡單介紹。

二、JuiceFS 架構與POC 測試

2.1 架構簡介

JuiceFS 將元資料資訊和真實資料塊分開管理,通過 FUSE 實現 POSIX 介面,允許使用者像本地檔案系統一樣使用。使用者將檔案寫入JuiceFS掛載的目錄後,檔案資料會儲存到物件儲存,相應的元資料(檔名、檔案大小、許可權組、建立修改時間和目錄結構等)會存到元資料引擎中。在該架構下,ls、資料刪除等操作只是對元資料引擎的操作,不受到物件儲存的速度限制,效能上會有較好的保證。

2.2 元資料引擎選型與測試

JuiceFS 的元資料引擎有很多選擇,包括開源的Redis、TiKV以及官方提供的閉源的企業版元資料引擎。考慮到攜程的資料規模較大並且後續會有更多的資料接入,元資料引擎需要能夠支援TB 級元資料的儲存並且能橫向擴容。因此TiKV和官方的企業版元資料引擎成了我們的備選方案。

為了驗證TiKV的效能,我們使用 go-ycsb做了一些效能測試。

機器

CPU

Memory

Storage

Network

Node1

2 Socket / 20 Core / 40 Thread

128G

1.9T SSD

bond0 25G

Node2

2 Socket / 20 Core / 40 Thread

128G

960G SSD

bond0 25G

Node3

2 Socket / 20 Core / 40 Thread

128G

1.2T SSD

bond0 25G

測試結果:

1)Write 事務寫入操作,隨著客戶端執行緒數增加,TPS上升,峰值超過30000

2)Get事務讀取操作, 隨著客戶端執行緒數增加,QPS上升,單節點峰值接近70000

從測試結果看,TiKV有較高的讀寫吞吐量,並且單次操作的響應時間P99<10ms,在冷資料場景中效能表現可滿足業務需求。

官方的企業版元資料引擎比TiKV有更好的效能表現,但是考慮到冷資料儲存對效能要求並不苛刻,而且相比於物件儲存20~200ms的訪問速度,元資料引擎並不會明顯降低整個系統響應的速度。為了減少技術黑箱,我們選擇了TiKV作為元資料引擎。

2.3 JuiceFS 整體POC測試

在交付生產之前,為了明確SLA指標和最佳使用場景,我們使用mdtest對以TiKV為元資料引擎的JuiceFS進行了整體POC 測試,部署使用如下架構:

1)單執行緒寫入,測試檔案大小與吞吐量的關係

測試結果表明隨著檔案大小增大,吞吐量也隨之增大。在單檔案為 128MB~256MB 左右時,原先的吞吐量與檔案大小的增長曲線明顯放緩。可以理解為當檔案較小時,JuiceFS客戶端與元資料引擎和物件儲存的互動成本與有效資料傳輸成本相比,佔比較高,限制了吞吐量;當檔案較大時,互動成本佔比降低,吞吐量上升。為了發揮充分JuiceFS的吞吐能力,建議儲存128MB以上的檔案。

2)目錄深度與 JuiceFS IOPS 的關係

測試結果表明目錄深度與 JuiceFS IOPS 沒有明顯關係。研究JuiceFS程式碼可知,雖然深度越深,檔案路徑變長,但 JuiceFS在建立檔案/目錄時在TiKV裡的Key是父目錄 inode + 新條目的名字,所以目錄深度不影響TiKV裡的鍵值對大小,就不影響TiKV的查詢效能,符合測試結果。

3)目錄大小與 ls速度的關係

單目錄下檔案個數

ls耗時(ms)

1025

25

24269

31

測試結果表明目錄下檔案個數對ls幾乎沒有影響。

2.4 元資料引擎故障測試

理論上TiKV 節點中 Region 通過 Raft 保證一致性,即非 Leader Region 故障完全不影響上層應用,Leader Region 故障則會在該 Region 的副本中重新選舉出一個 Leader Region,選舉需要時間,並且需要上報 PD 節點進行處理,因此會影響到上層應用的部分請求。

PD 叢集用來管理 TiKV 叢集,PD 的非 Leader 節點故障完全不影響上層應用,Leader 節點故障則需要重新選舉新 PD Leader,選舉過程 JuiceFS 客戶端的請求無法得到響應,新 Leader 節點確立後 JuiceFS 重新建立連線也需要一定耗時,該時間段內會對上層應用的請求產生影響。

據此我們模擬節點故障的場景,測試實際應用過程中元資料引擎故障後恢復所需時間,計算正常場景中讀寫一定數量檔案與異常情況下的耗時差異。結果表明故障影響時間可以控制在秒級。

1)TiKV 故障

File size/count

正常

異常

Diff(ms)

單執行緒寫 4MiB/1024

237035.52

249333.76

12298.24

單執行緒讀 4MiB/1024

360222.72

362577.92

2355.2

2)PD 故障

File size/count

正常

異常

Diff(ms)

單執行緒寫4MiB/1024

237035.52

247531.52

10496

單執行緒讀 4MiB/1024

362332.16

362577.92

245.76

三、JuiceFS原理解析

3.1 檔案寫入

JuiceFS 接收到寫請求會先將資料寫入 Buffer,並按照 Chunk、Slice、Block 的規則進行資料塊管理,最後以 Slice 為維度Flush到物件儲存。一次 Flush 實質上是對 Slice 中的每個 Block 進行 PUT 操作,將資料寫到物件儲存,並完成元資料修改。如下圖:

  • 大檔案先經過 FUSE 處理成 128K 的塊,在JuiceFS內部拼成一個個4M大小的Block,Slice 管理的Block不斷增加,直到 Slice 達到 64M(即一個 Chunk 的大小),觸發一次 flush操作。Chunk、Slice、Block 的拼裝使用的是記憶體buffer,其大小受JuiceFS啟動引數buffer-size 的限制。
  • 小檔案由新的 Slice 單獨管理,在檔案寫入完成時被上傳到物件儲存。
  • 如果客戶端設定 writeback 模式,JuiceFS 不會直接寫資料到 Object Storage,而是寫到 JuiceFS 所在機器的本地磁碟,後續非同步寫到物件儲存。這種方式存在丟資料的風險,但是可以提升資料寫入速度。

3.2 檔案讀取

讀取流程資料處理方式與寫入流程類似,讀取請求被 JuiceFS 程序接收到後會先訪問元資料引擎,找到需要讀取的 Block,向物件儲存併發發出 GET 請求。由於 Block 資料不變性,讀取出的 4M 的 Block 會寫到本地的快取目錄中。讀取過程中按照 4M(Block) 的方式實現了一定程度的預讀,可以通過調整 prefetch 引數,將預讀視窗設定的更大,預設 prefetch = 1。如下圖:

  • 大檔案順序讀場景下,會讀取物件儲存中4M 大小的物件,經過 FUSE 處理成 128K 的塊返回給使用者。此場景中快取命中率會很高,由於預讀和本地Block快取,吞吐效能較好。
  • 大檔案隨機讀場景下流程和順序讀一致,該場景下的預讀、快取被命中的概率很低,這些邏輯反而可能影響讀取效能(需要將讀取到的資料寫入本地快取目錄),可以通過設定 cache-size = 0 關閉快取。
  • 小檔案(例如 4K)讀取場景下,會讀取當前檔案的 Block,經過 FUSE 後響應給使用者程式。獲取到的資料也會寫到本地快取目錄中。

四、故障處理與效能優化

4.1 TiKV CPU使用率過高,導致拒絕服務

現象:TiKV kv_scan請求數突然上升,unified_read_po 執行緒池CPU使用率被打滿

分析:客戶端執行cleanTrash任務導致的。Beta 1版本的客戶端會同時進行該任務,當同一個volume掛載的客戶端較多,並且trash中的資料量非常多的時候,該任務會對元資料引擎造成突發的壓力。

解決方案:

  • 增加客戶端對元資料引擎各個介面的呼叫量監控,便於快速診斷是哪些客戶端導致的問題;
  • 將後臺任務從客戶端中剝離,客戶端只需要執行使用者的請求,cleanTrash這樣的後臺任務交給單獨的元件執行,便於JuiceFS管理員控制;
  • 升級客戶端,Beta3開始增加了分散式鎖,並且增加了no-bgjob啟動引數。

4.2 TiKV 資料洩露

現象:檔案數目和OSS中的資料量沒有增加的情況下,region數目不斷增加,store size不斷增加

分析:通過tikv-ctl檢視TiKV裡的資料,發現MVCC的修改和刪除記錄沒有被清除。完整的TiDB部署會10min觸發一次資料GC。但是單獨部署TiKV,資料GC需要由其他程式觸發。另一方面5.0.1版本的TiKV有bug,資料GC沒有清理刪除記錄,相關issue。

解決方案:

  • 參考http://github.com/tikv/client-go/blob/v2.0.0/examples/gcworker/gcworker.go單獨實現一個元件,定期呼叫GC功能
  • 升級TiKV到5.0.6

4.3 CSI 掛載場景中,PV 清理後資料 OSS 中資料無法回收

現象:k8s中的ElasticSearch 所有Pod、PVC、PV 下線一天後 OSS 資料仍沒被清理。

分析:PV 被清理時 CSI 執行了 JuiceFS rmr 指令,將 volume 資料全部放到回收站,根據預設配置 trash-day=1,即一天後開始回收資料。由於環境中的 JuiceFS mount Pod 已經全部下線,即沒有 JuiceFS 程序掛載了 CSI 的 volume,於是出現了沒有清理回收站的情況。

解決方案:由於 CSI 模式使用 JuiceFS 是模擬了 subdir 的過程,即整個 CSI 管理 Pod 掛載的 volume 是同一個,通過寫到子目錄的方式進行資料隔離。我們停止了mount pod的所有後臺任務,另外找了一臺機器掛載該 volume來完成自動清理回收站資料等後臺任務,該方法也消除了後臺任務帶來的客戶端效能抖動。

4.4 客戶端使用記憶體過高

現象:部分使用 JuiceFS 的機器佔用記憶體過高,達到了 20GB+。

分析:

  • 通過 cat /proc/$pid/smaps 檢視,發現佔用的記憶體都是 Private_Dirty,說明是被 JuiceFS 程序長期持有,不是 Page Cache 快取佔用導致。
  • 通過使用 pprof 工具分析 heap 佔用情況,可推測出是 dump meta(backup)導致的異常。

解決方案:將客戶端的啟動引數backup-meta預設值改為0,元資料備份參考官方的實現思路通過另外的元件統一實現,客戶端不執行元資料備份任務。

4.5 優化後架構

生產實踐過程中涉及數PB級的資料,業務場景相差巨大,經過規劃與調優,最終演進成如下架構。

  • 量級較小的業務由使用者掛載的JuiceFS client治理session、trash等資料。
  • 量級較大的業務(PB級、數百client級)掛載的client不處理session、trash等資料的清理(開啟no-bgjob引數),由admin 提供一個client單獨處理,並提供清理加速的能力。
  • 提供了一個client統一做同一tikv叢集內所有volume的backup-meta操作。
  • 提供訪問OSS和TIKV叢集的限流能力,通過命令下發修改client的限流能力,用於在必要情況下保護專線頻寬、元資料庫,實現服務降級。
  • 使用多套元資料叢集用來隔離行為差異較大的業務。
  • 提供服務觸發TiKV的GC。

五、總結與展望

通過 JuiceFS 將冷資料上公有云, Elasticsearch 實現了一定程度的存算分離,去除了副本帶來的記憶體需求,提升整體叢集資料儲存能力。DBA 備份資料從 GlusterFS 遷移到 JuiceFS 後 ls 等行為的效能大幅提高,不僅運維人員不再需要投入精力進行磁碟擴容維修,大大降低了運維成本,而且使用者還能夠按照保留時間快速地控制儲存成本。

目前已有2PB 來自 ElasticSearch、DBA 備份的資料儲存到JuiceFS,後續我們會推動更多的資料上JuiceFS,當然後續也很多需要進一步探索和優化的地方,例如:

  • 進一步優化元資料引擎 TiKV 的效能與提升 JuiceFS 的穩定性,以應對10PB+的資料量
  • 探索JuiceFS在ClickHouse冷資料儲存上的使用方法
  • 公有云場景下使用JuiceFS替換HDFS,以降低雲上的儲存成本