Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用

ITPUB社群發表於2022-11-30

背景

Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用如果想及時瞭解Spark、Hadoop或者HBase相關的文章,歡迎關注微信公眾號:過往記憶大資料

在 Uber,資料影響著每一個決定。Presto 是推動 Uber 各種資料分析的核心引擎之一。例如,運營團隊在儀表盤等服務中大量使用 Presto;Uber Eats 和營銷團隊依靠這些查詢的結果來決定價格。此外, Presto 還被用於 Uber 的合規部門、增長營銷部門和臨時資料分析。

Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用如果想及時瞭解Spark、Hadoop或者HBase相關的文章,歡迎關注微信公眾號:過往記憶大資料

Uber 的 Presto 規模很大。目前,Presto 有9000個日活躍使用者,每天處理500K次查詢,處理超過 50PB 的資料。Uber 的基礎設施包括兩個資料中心,7000個節點和跨越兩個地區的20個 Presto 叢集。

Uber 的 Presto 部署

當前架構

Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用如果想及時瞭解Spark、Hadoop或者HBase相關的文章,歡迎關注微信公眾號:過往記憶大資料

UI/客戶端層:這包括內部儀表板、Google Data Studio、Tableau 和其他工具。此外,我們還有一些使用 JDBC 或查詢解析與 Presto 通訊的後端服務。路由層:這一層負責將查詢分配到不同的 Presto 叢集。路由是基於從每個 Presto 叢集提取的統計資料,包括查詢和任務的數量、CPU 和記憶體使用情況等等。我們根據這些統計資訊確定每個查詢應該路由到哪個叢集。換句話說,這一層充當負載均衡和查詢攔截的服務。Presto 叢集:在底部,多個 Presto 叢集與底層 Hive、HDFS、Pinot 等進行通訊。Join 操作可以在不同的 connectors 或不同的資料集之間執行。

此外,對於上述架構的每一層,我們有:

內部監控支援使用 Kerberos

Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用Presto 工作負載分為兩類:

互動式的:由資料科學家和工程師傳送的查詢;定時任務:主要是定期迴圈的批次查詢,包括 Dashboard, ETL等。

使用 Alluxio 進行本地快取

最近,我們將 Alluxio 部署在我們三個生產環境的叢集中,每個叢集有200多個節點。我們使用的是 Alluxio Local Cache 模式,它利用 Presto worker 的本地 NVMe 磁碟。我們不是快取所有資料,而是透過選擇性快取其中一部分資料。

下圖是將 Alluxio 作為 Local Cache 的示意圖。Alluxio Cache Library 是一個執行在 Presto worker 內部的本地快取,我們在預設的 HDFS 客戶端之上實現了一個層。

Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用當任何外部 API 從 HDFS 呼叫中讀取資料時,系統首先檢視快取,看看是否命中快取,如果命中,它將直接從本地 SSD 中讀取資料。否則,它將從遠端 HDFS 讀取資料,並在本地快取資料以備下一次讀取。在此過程中,快取命中率對整體效能有重要影響。

我們將在下面討論 Alluxio Local Cache 的詳細設計和改進。

主要挑戰和解決方案

挑戰1:實時分割槽更新

我們遇到的第一個挑戰是實時分割槽更新。在 Uber,很多表/分割槽都在不斷地變化,因為我們不斷地將資料插入 Hudi 表。

挑戰在於,僅使用分割槽 ID 作為快取鍵是不夠的。同一個分割槽可能在 Hive 中發生了變化,而 Alluxio 仍然快取過時的版本。在這種情況下,快取中的分割槽已經過時,因此如果資料來自快取,那麼在執行查詢時,使用者將得到過時的結果,從而導致不一致的體驗。

解決方法:將 Hive 的最新修改時間新增到快取 Key 中

我們的解決方案是為快取的 Key 新增最新的修改時間,如下所示:

之前的快取 key 為: hdfs://<path>現在的快取 Key 為:hdfs://<path><mod time>

Presto 目前可以透過 HDFS API 獲取每個 Hive 分割槽檔案的最新修改時間。具體來說,在處理 split 時,Presto worker 會顯式呼叫 HDFS listDirectory API,作為 HDFS 返回的資訊的一部分,有檔案的最新修改時間。透過此解決方案,快取了最新修改的新分割槽,確保使用者始終獲得其資料的一致檢視。注意,可能存在一個競態條件視窗,在 Presto worker 獲得最新的修改時間後,遠端檔案再次更新,而 Presto worker 仍然錯過最新的更改。一方面,在如此短的時間間隔內進行兩次連續更新是罕見的;另一方面,這樣的場景並不比沒有快取的情況差,但是在查詢執行期間更改了表目錄。在這種情況下,即使是現有的非快取執行也會導致不一致的行為。另一個注意事項是有一個權衡:過時的分割槽仍然存在於快取中,浪費快取空間,直到刪除。目前,我們正在努力改進快取清除策略。

挑戰2:叢集節點變更

在 Presto 中,Soft Affinity 排程是透過簡單的、基於求模的演算法實現的。該演算法的缺點是,如果新增或刪除一個節點,整個環將被不同的快取鍵打亂。因此,如果一個節點加入或離開叢集,它可能會損害所有節點的快取命中率,這是有問題的。

為了提高快取命中率,在 Presto 中讀取給定分割槽的資料會定位到相同的節點。雖然這很好,但問題是 Presto 之前使用了一個簡單的雜湊函式,當叢集發生變化時,這個函式可能會失效。

如下所示,目前,我們使用一個簡單的基於雜湊 mod 的節點查詢:key 4 % 3 nodes = worker#1。現在 worker#3 當機,新的查詢為:key 4 % 2 nodes = worker#0,但 worker#0 沒有快取相關的資料。

Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用如果想及時瞭解Spark、Hadoop或者HBase相關的文章,歡迎關注微信公眾號:過往記憶大資料

解決方案:基於節點 id 的一致性雜湊

一致雜湊(Consistent hashing)是解決方案。與基於求模的功能不同,所有節點都放在一個虛擬環上。無論節點加入或離開,環上節點的相對順序都不會改變。我們總是查詢環上的鍵,而不是使用求模得到的 hash 值。我們可以確保無論做了多少更改,它們總是基於相同的節點集。此外,我們使用複製來提高健壯性。這是解決叢集成員問題的解決方案。

Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用

挑戰3:快取大小限制

Uber 的資料湖規模比較大,Presto 叢集每天掃描50PB的資料。但是,我們的本地磁碟空間每個節點只有 500 GB。Presto 查詢訪問的資料量遠遠大於 Worker 節點上可用的磁碟空間。儘管可以將所有內容都放入快取中,但經常清理快取可能會損害整體快取效能。

解決方案: Cache Filter

其思想是隻快取選定的資料子集,其中包括某些表和一定數量的分割槽。解決方案是開發一個 cache filter,這是一種決定是否快取一張表以及快取多少個分割槽的機制。下面是一個配置示例:

Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用

如果想及時瞭解Spark、Hadoop或者HBase相關的文章,歡迎關注微信公眾號:過往記憶大資料

cache filter 大大提高了快取命中率,從~65%提高到>90%。下面是 cache filter 需要注意的幾個方面:

它是手動、並且是靜態配置需要根據訪問頻率進行設定最常訪問的表;需要根據訪問頻率進行設定不經常更改的表理想情況下,應該基於 shadow caching 的資料和表級指標。

我們還透過監控/儀表板實現了可觀察性,它與 Uber 的內部指標平臺整合,使用傳送到基於 grafana 的儀表板的 JMX 指標。

Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用

後設資料最佳化

在下面的小節中,我們將討論對本地快取後設資料的改進。

本地快取的檔案級後設資料

動機

首先,我們希望防止過時的快取。底層資料檔案可能由第三方框架更改。注意,這種情況在 Hive 表中可能很少見,但在 Hudi 表中很常見。

其次,每天從 HDFS 讀取的非複製資料可能很大,但我們沒有足夠的快取空間來快取所有資料。因此,我們可以透過為每個表設定配額來引入範圍配額管理。

第三,後設資料應該在伺服器重新啟動後可以恢復。我們將後設資料儲存在記憶體而不是磁碟中的本地快取中,這使得在伺服器關閉並重新啟動時不可能恢復後設資料。

高階別的方法

因此,我們提出檔案級後設資料(file-level metadata),它儲存檔案的最後修改時間和快取的每個資料檔案的範圍。檔案級後設資料儲存應該持久儲存在磁碟上,這樣資料才不會在重新啟動後消失。

隨著檔案級後設資料的引入,資料將有多個版本。當資料更新時,會生成一個新的時間戳,對應於一個新的版本。一個儲存新 page 的新資料夾將根據這個新時間戳建立。同時,我們將嘗試刪除舊的時間戳。

快取資料和後設資料結構

Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用如上所示,我們有兩個資料夾對應兩個時間戳:timestamp1 和 timestamp2。通常,當系統執行時,不會同時有兩個時間戳,因為我們將刪除舊的 timestamp1,只保留 timestamp2。然而,在繁忙的伺服器或高併發性的情況下,我們可能無法刪除舊時間戳的資料,在這種情況下,我們可能同時有兩個時間戳的資料。此外,我們維護一個後設資料檔案,其中包含 protobuf 格式的檔案資訊和最新的時間戳。這確保了 Alluxio 的本地快取只從最新的時間戳讀取資料。當伺服器重新啟動時,從後設資料檔案中讀取時間戳資訊,以便正確管理配額和最後修改時間。

Metadata 感知

Cache Context

由於 Alluxio 是一種通用的快取解決方案,它仍然需要計算引擎(如 Presto)將後設資料傳遞給 Alluxio。為此,我們在 Presto 端實現了 HiveFileContext。對於 Hive 表或 Hud i表中的每個資料檔案,Presto 都會建立一個 HiveFileContext。在開啟 Presto 檔案時,Alluxio 會使用這些資訊。

當呼叫 openFile 時,Alluxio 建立一個 PrestoCacheContext 的新例項,它儲存 HiveFileContext,並具有作用域(4個級別:database, schema, table, partition)、quota、快取識別符號(即檔案路徑的 MD5 值)和其他資訊。我們將把這個 cache context 傳遞給本地檔案系統。因此,Alluxio 可以管理後設資料並收集指標。

Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用

Presto 側的每個查詢指標聚合

除了將資料從 Presto 傳遞到 Alluxio 之外,我們還可以回撥 Presto。在執行查詢操作時,我們將知道一些內部指標,例如有多少位元組的資料讀取到快取中,有多少位元組的資料從外部 HDFS 儲存中讀取。

如下所示,我們將包含 PrestoCacheContext 的 HiveFileContext 傳遞給本地快取檔案系統(LocalCacheFileSystem),之後本地快取檔案系統回撥(IncremetCounter)給 CacheContext。這個回撥鏈將繼續到 HiveFileContext,然後到 RuntimeStats。

Alluxio Local Cache 加速 Presto 查詢在 Uber 的應用在 Presto 中,RuntimeStats 用於在執行查詢時收集度量資訊,以便我們可以執行聚合操作。之後,我們可以在 Presto 的 UI 或 JSON 檔案中看到關於本地快取檔案系統的資訊。我們可以讓 Alluxio 和 Presto 在上述過程中緊密配合。在 Presto 方面,我們有更好的統計資料;在 Alluxio 方面,我們對後設資料有了更清晰的瞭解。

未來工作

下一步

首先,我們希望快取更多的表,並透過自動化改進表的快取過程,Alluxio Shadow Cache (SC) 將在這方面有所幫助。其次,我們希望對不斷變化的分割槽/Hudi 表有更好的支援。最後,負載均衡是我們可以實現的另一個最佳化。我們的旅程還有很長的路要走。

隨著計算-儲存分離以及大資料容器化繼續成為趨勢,我們相信像 Alluxio 這樣連線計算和儲存的統一層將繼續發揮關鍵作用。

效能調優

由於上述回撥過程使 CacheContext 的生命週期顯著增長,我們遇到了一些 GC 延遲上升的問題,我們正在努力解決。

Adopt Semantic Cache (SC)

我們將根據我們建議的檔案級後設資料來實現語義快取(SC)。例如,我們可以將資料結構儲存在 Parquet 或 ORC 檔案中。

更高效的反序列化

為了實現更有效的反序列化,我們將使用flatbuf而不是protobuf。儘管在ORC工廠中使用protobuf來儲存後設資料,但我們發現在Alluxio與Facebook的合作中,ORC的後設資料帶來了超過20-30%的CPU使用總量。因此,我們計劃用flatbuf替換現有的protobuf來儲存快取和後設資料,預計這將顯著提高反序列化的效能。

為了實現更高效的反序列化,我們將使用 flatbuf 代替 protobuf。雖然在 ORC factory 中使用了 protobuf 來儲存後設資料,但我們發現在 Alluxio 與 Facebook 的合作中,ORC 的後設資料帶來了超過 20-30% 的總 CPU 使用率。因此,我們計劃用 flatbuf 替換現有的 protobuf 來儲存快取和後設資料,這有望顯著提高反序列化的效能。

總結

在本文中,我們討論了 Uber Presto 快取解決方案的設計和實現,以提高 Uber 在各種用例中的互動式查詢效能。我們分享了 Presto 在 Uber 採用 Alluxio Local Cache 的歷程,討論了我們如何定製和擴充套件現有解決方案,以解決我們遇到的特定於 Uber 規模和用例的挑戰。該解決方案已在生產環境中執行超過四分之一,並且維護開銷最小。

本文翻譯自:《Speed Up Presto at Uber with Alluxio Local Cache》https://www.uber.com/blog/speed-up-presto-with-alluxio-local-cache/

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2925882/,如需轉載,請註明出處,否則將追究法律責任。

相關文章