好的數據編排怎么做?平安壹錢包大數據重構實踐
一、Alluxio 介紹
1、背景介紹
當前計算引擎越來越多樣化,存儲系統和部署環境也越來越復雜。不同的計算和存儲適用于不同的場景。比如 Presto 的即席查詢性能比較好,比 Spark 要快很多,而 Spark 又更適合于批量處理。存儲系統也是一樣的,常用的 HDFS 是一個可以存取海量數據的存儲系統,但有些場景下又希望能夠使用存儲密度更高的存儲系統。與此同時,部署方式也在不斷變化,比如之前一般使用的是 CDH,將來可能會用 Ambari 這樣一個開源的方式,還可能會考慮使用容器化的部署,為將來的云化做一個鋪墊。
環境的日趨復雜化,帶來了很多問題與挑戰。比如我們在實踐過程中,為了建設數據湖倉,必須要引入 Iceberg,但是已有的 HDFS 是 2.6.x,Spark 是 1.6.x,對 Iceberg 是不支持的。為了引入 Iceberg,HDFS 要升級到 3.x,Spark 也要升級,才能建設成一個整體。
在這樣一個過程中,我們面對了四點比較突出的問題:
- 高耦合:計算引擎與存儲系統已經形成了一個整體,任意一方的升級或者變更,都意味著需要重新考慮兼容性的問題。
- 難迭代:計算引擎需要使用不同 API 去訪問不同的存儲系統,數據的跨存儲系統遷移往往需要兼顧計算機應用,甚至需要重新開發。
- 難遷移:從本地集群的部署方式平滑遷移為云部署的難度高,不僅維護成本高,還很難適應混合云環境。
- 持續性的迭代壓力:任何方案都會過時,想要追逐技術前沿,就需要面對持續性的迭代壓力。
2、數據編排概覽
Alluxio 是一種基于數據編排技術的開源組件。
數據編排技術是位于存儲層與計算層之間的一個抽象層。它可以將復雜多樣的底層存儲進行包裝,向上提供統一的訪問路徑,兼容多種訪問協議,以應對多樣化的存儲需求與應用計算之間的矛盾。為數據驅動的應用程序提供數據可訪問性、數據本地性和數據可伸縮性。
Alluxio 可以帶來如下一些好處:
- 標準 API
Alluxio 可以跨存儲系統將數據訪問抽象出來,計算引擎只需使用標準 API 就可以訪問不同存儲系統中的數據。
- 解耦計算與存儲
Alluxio 允許掛載多個不同的存儲系統以及不同版本的相同存儲系統,解耦計算與存儲,方便存儲系統的升級和引入過程。
- 緩存
Alluxio 具有緩存功能,加速訪問熱數據。
- 云原生
Alluxio 是云原生的,可以在任何云中快速搭建數據編排層。
Alluxio 為數據驅動型應用和存儲系統構建了橋梁,使得應用程序能夠通過一個公共接口連接到多種存儲系統。與此同時,Alluxio 內存至上的層次化緩存架構使得數據的訪問速度比現有方案快幾個數量級,非常適合 IO 成為瓶頸的存算分離場景。
Alluxio 的最上層是計算層,最底層是存儲層,中間是數據編排層。計算層通過多種標準數據訪問 API 來訪問數據編排層。編排層負責對多種存儲系統的訪問。
3、Alluxio 架構設計
計算應用通過 Alluxio Client從Alluxio Master 獲取 AlluxioWorker 節點與默認配置,并與 Worker 建立連接進行數據讀寫。在這個過程中,Alluxio Client 會將計算應用的 API 進行自動轉換,讓整個過程對于計算應用是透明的。
Alluxio Master 基于 zookeeper 或者內嵌的 Raft 服務實現 HA,并負責維護默認配置、協調 Worker 節點、接收請求、塊位置等工作。
Alluxio Worker 的職責包括:
- 跨存儲系統的數據讀寫:Alluxio Worker 主要負責與底層存儲系統進行交互,它不僅實現了不同存儲系統的 API,還可以自動轉換,實現了跨存儲系統的數據讀寫。
- 多級緩存:Alluxio Worker 維護了一個多級緩存,用以加速熱數據的訪問,減少讀取底層存儲的次數。而基于塊注釋的緩存設計,不僅可以為熱數據提供最佳性能,還能在緩存空間不足時自動釋放較冷的數據,以非常自然的方式實現了數據的冷熱分離。
- 訪問短路:當計算應用與 Alluxio Worker 處于同一節點時,還可以直接通過 NIO 進行短路交互,進一步優化數據的訪問鏈路,減少響應時間。
- 彈性部署:Alluxio Worker 在啟動時會主動向 AlluxioMaster 注冊自己,并通過心跳機制維持存在,而基于數據易失性的設計,可以讓用戶根據需要,靈活的進行水平拓展或者縮容。
4、Alluxio 核心功能
(1)統一命名空間
- 靈活掛載
Alluxio 的根掛載點需要在啟動時指定,綁定 Alluxio 的根目錄。嵌套掛載點則可以在任意 Alluxio 子目錄上通過命令行指定。嵌套掛載點的數量沒有限制,可以分別掛載不同的存儲系統,或者相同存儲系統的不同版本。 - 訪問控制
用戶通過 Alluxio 訪問底層存儲時,只能訪問掛載在 Alluxio 上的目錄,同時 Alluxio 也可以將掛載點設定為 read-only,進一步限制用戶對底層存儲的訪問。這是區別于用戶權限管理的強制限制。 - 訪問透明
用戶通過 Alluxio 訪問底層存儲時,并不需要感知底層存儲系統的類別、版本,也不需要關注掛載點(某些情況除外)。在大部分場景中,通過 Alluxio,用戶可以無感知地訪問掛載其上的底層存儲。
(2)緩存
- 緩存讀寫策略
讀:NO_CACHE(Alluxio 僅作為代理,不做緩存),CACHE_PROMOTE(盡量放到緩存最上層),CACHE。
寫:THROUGH(Alluxio 僅作為代理,不做緩存),CACHE_THROUGH(寫入存儲時備份到緩存空間中,適合于寫入后還需要讀的場景),ASYNC_THROUGH(異步寫),MUST_CHACHE(僅寫入緩存空間)。 - 緩存管理
塊注釋策略:根據塊注釋策略為數據塊進行排序,位于序列尾部的數據塊將作為優先的空間釋放對象。
最少最近策略
基于權重的最少最近策略
緩存分層:數據塊可能已配置存儲層中,基于塊注釋策略,Alluxio 會在各存儲層中移動數據塊,包括塊對齊、塊升級、遷移任務退后等。
緩存驅逐:當 Alluxio 的存儲空間不足時,無法接受新數據的寫入,會基于注釋策略釋放存儲空間,這個過程叫做緩存驅逐。它保證了 Alluxio 總是存儲著熱數據,但也會在某些場景下造成緩存命中率降低的問題。 - 緩存生命周期
數據操作:LOAD(加載數據到緩存空間),PERSIST(緩存空間中的數據回寫到底層存儲),FREE(只清除緩存空間中的數據,不動底層存儲數據),DELETE(緩存空間和底層存儲的數據都清除)
TTL:Alluxio 可以為文件和目錄設置生存時間,當生存時間到達時,執行一種數據操作,默認為 DELETE。這樣可以對緩存空間進行策略化管理。
元數據同步:Alluxio 可以為文件和目錄設置元數據檢查周期,當緩存過期時,會自動從 UFS 重新加載。如果每次訪問都同步底層存儲,開銷會比較大,因此可以根據應用場景進行定制。如果對數據時效性比較敏感,底層存儲的任何更新,在通過 Alluxio 去訪問時都希望能感知到,這時就可以設置每次讀之前同步元數據。而大多數情況下,對數據時效性沒有那么敏感,那么就可以根據需要設置同步的時間間隔。
二、Alluxio 實踐分享
1、長鏈計算任務的遷移需要兼顧上下游依賴關系
建設湖倉一體化,不可避免的一個問題就是如何去做數據遷移,以及生成這個數據的長鏈任務的遷移。如果沒有數據編排層去做遷移,需要兼顧上下游的數據關系。有了編排層,如圖所示,首先將舊集群中的數倉和新的湖倉進行元數據同步,可以看到舊的數倉和新的湖倉均含有兩張表,但實際上從底層來看,這兩張表的數據只維護了一份,好處是不需要在兩個集群里面都維護相同的數據,減少了存儲的壓力,同時可以避免數據不一致的問題。通過 Alluxio 將元數據同步,做遷移時就可以只遷移該任務所依賴的數據本身,這樣任務遷移就變得非常靈活。
2、利用高速的緩存空間加速數據的讀寫
在加速場景里面,我們根據不同的應用場景,使用不同的 Alluxio 集群。
- 將 Trino 和 Alluxio 混合部署在 SSD 集群上(混合部署時性能最佳),利用 Alluxio 緩存空間加速熱數據的加載。
- 對于熱度不高的數據也可以通過直連底層存儲進行訪問。
- Spark shuffle 加速主要基于 Spark RSS 這邊的接口,每個公司使用不同的產品,Alluxio 集群可以整合空閑的內存或是零散的 SSD 空間,把這些空間充分地利用起來。
- 利用 Alluxio 可以將 RSS 產生的 IO 占用限制在指定集群、節點或者磁盤上,減少集群的 IO 競爭帶來的任務時長波動。
3、提供數據本地性,將需要單點部署的應用與大數據存儲直接連通
(1)痛點:
- 有些 AI 計算需要部署在裝有 GPU 的特定機器上,與大數據集群環境天然隔離;
- 算法工程師需要學習并實現特定存儲系統的 API 才能去讀寫數據;
- 部分計算應用需要將原始數據拉取到本地才能進行計算,但是本地節點的磁盤空間有限。
(2)優化:
- Alluxio 支持 POSIX API,它可以直接 mount 到本地節點的目錄上,連通大數據存儲與本地節點。
- 算法工程師可以像讀寫本地文件一樣讀寫大數據存儲上的數據,而不必關注遠端存儲系統,從而節省學習和開發成本。
- 為本地節點提供集群級別的存儲空間,并提供最高內存級別的數據讀寫速度。
4、兩種實現冷熱分離的架構
Alluxio 實現冷熱分離有兩種方式,一種方式是可以在存儲層做冷熱分隔。如果一個集群性能比較高,主要是熱數據,另一個集群數據都是冷數據,但是存儲密度高。當數據變冷時,需要人工將數據從高性能的集群遷移到高存儲密度的集群,從而實現冷熱分離,這樣對于上層應用不太友好,底層數據在遷移的時候,目錄、命名空間不一樣,用 Alluxio 就可以避免這些問題。在此過程中 Alluxio 僅需要作為一個代理,不需要緩存空間,僅需要滿足 IO 計算。這種方式對 Alluxio 本身的緩存能力沒有很高的要求。
第二種方式是利用 Alluxio 直接做一個上下層的冷熱分離,在此過程中 Alluxio 作為編排層,直接放熱數據,存儲層直接放冷數據。冷數據可以通過預加載的方式暖起來,把數據寫進緩存空間。這種方式需要 Alluxio 提供一個較大的緩存空間。
實踐中,我們綜合使用了兩種方式。整體上是以第一種方式為主,我們有一個高性能的集群和一個高存儲密度的集群。與此同時,也為 Alluxio 配置了一些緩存空間,來進一步提升性能。
5、大數據架構演變
Alluxio 帶來的大數據架構演變過程如上圖所示。
- 引入Alluxio,實現緩存加速。
- Alluxio 掛載多個存儲系統,助力存儲升級和數據遷移,數據在邏輯層面實現存算分離。
- 將計算應用做容器化改造,與 Alluxio 一起遷移到 K8s 中,完全實現存算分離,具備上云的條件。
- 根據業務需求,為不同的計算應用單獨定制 Alluxio 集群,滿足個性化需要。
三、展望
最后來分享一下未來的規劃。
1、更輕:輕量部署無負重
通過引入 Alluxio,我們可以將計算應用與存儲系統解耦,進而減少大數據架構迭代的難度和成本。Alluxio 的部署已經足夠靈活簡單,但我們仍然希望有更輕量、更無侵入的部署方式或配置項:
- 更靈活的邏輯域名配置項,避免修改 core-site.xml
- 客戶端級別的可配置化的訪問映射,避免修改 HMS
- 集成度更高的服務端進程
2、更快:讓快變得更快
通過利用 Alluxio 的緩存空間,計算應用可以獲得最高內存級別的讀寫加速,并減少與底層存儲的 I/O 吞吐,獲得全方位的數據加速體驗。但在復雜的部署環境中,我們希望獲得一些新的特性,讓快變得更快。
- 更豐富的緩存請求分配策略(例如給 LocalFirst 增加備選策略)
- 跨集群數據讀寫的 I/O 限流
- 基于客戶端的 UFS 讀寫(例如客戶端從 worker 獲取掛載信息和配置后自己去讀)
3、更穩定:穩定可靠控風險
通過引入 Alluxio,我們將存儲系統置于更底層,由 Alluxio 與計算應用進行交互,這帶來了許多穩定性上的好處,例如審計日志、Metrics、訪問控制等等,但也帶來了一些新的挑戰,等待我們去探索更穩定的集群環境:
- 基于 tag 或者用戶組的緩存配額
- AlluxioWorkerJVM 與 RAM 緩存的內存統一
- 本地緩存數據的故障載入