博客 / 詳情

返回

Meta公司新探索 | 利用Alluxio數據緩存降低Presto延遲

概要速覽📕

Meta公司(前“Facebook公司”,下文統稱“Meta”)的Presto團隊一直在與Alluxio 合作為Presto提供開源數據緩存方案。該方案被用於Meta的多個用例,來降低從諸如HDFS等遠端數據源掃描數據產生的查詢延遲。實驗證明,使用Alluxio數據緩存後,查詢延遲和IO掃描都得到了顯著優化。

我們發現,Meta架構環境中的多個用例都得益於Alluxio數據緩存。以Meta的一個內部用例為例,其各分位的查詢延遲分別下降了33%(P50)、54%(P75)和48%(P95)。此外,遠端數據源掃描數據的IO性能提升了57%。

Presto架構📖

Presto的架構允許存儲和計算獨立擴展,但是掃描遠端存儲中的數據可能會產生昂貴的操作成本,也難以達到交互式查詢的低延遲要求。

Presto worker只負責對從獨立(通常是遠端)數據源掃描的數據執行查詢計劃片段,而不會存儲任何遠端數據源的數據,因此計算可以進行彈性擴展。

下面的架構圖清晰地展示了從遠端HDFS讀取數據的路徑。每個worker都會獨立地從遠端數據源中讀取數據,本文將只討論對遠端數據源讀取操作的優化。
image.png

Presto +數據緩存架構📖

為了解決用例的亞秒級延遲問題,我們決定進行多種優化,其中一個重要的優化就是實現數據緩存。數據緩存作為一種傳統的優化方式,能讓工作數據集更靠近計算節點,減少對遠端存儲的訪問,從而降低延遲並節約IO開銷。

其中的困難在於,如果從遠端數據源訪問PB級別的數據時沒有固定訪問模式的話,如何能實現有效的數據緩存,此外,有效數據緩存的另一個要求是在Presto等分佈式環境中實現數據的親和性。

添加數據緩存功能後,Presto的架構如下所示:
image.png

關於數據緩存,後面會有更詳細的説明。

軟親和調度📖

Presto目前的調度器在分配分片時已經把worker的負載納入考量,因此該調度策略使得工作負載在worker之間均勻分配。但從數據本地性的角度來看,分片是隨機分配的,不能保證任何親和性,而親和性恰恰是實現有效數據緩存的必備條件。對Coordinator而言,每次把分片分配給同一個worker至關重要,因為該worker可能已經緩存了分片所需的數據。
image.png

上圖説明了親和性調度是如何給worker分配分片的。

執行軟親和調度策略時,會盡可能將同一個分片分配給同一個worker。軟親和調度器使用分片的哈希值來為分片選擇一個首選worker,軟親和調度器:

✓ 為分片計算其首選worke。如果首選worker有充足的可用資源,那麼調度器會把該分片分配給首選worker。
✓ 如果首選worker處於忙碌狀態,那麼調度器就會選擇一個備選worker,如果該備選worker有充足的可用資源,調度器就會把分片分配給它。
✓ 如果備選worker也處於忙碌狀態,那麼調度器就會把分片分配給當前最空閒的worker。
image.png

確定一個節點是否忙碌可通過兩項配置來定義:

✓ 單節點最大分片數:node-scheduler.max-splits-per-node
✓ 單任務最大待定分片(pending split)數: node-scheduler.max-pending-splits-per-task

當某一節點上的分片數超過上述任一配置的限制時,該節點就被視為忙碌節點。可以看出,節點親和性對於緩存的有效性至關重要。如果沒有節點親和性,同一分片可能會在不同的時間被不同的worker處理,這會導致冗餘的分片數據緩存。

出於這個原因,如果親和性調度器沒能把分片分配給首選worker或者備選worker(因均處於忙碌狀態),調度器就會向被分配的worker發出信號,讓其不要緩存分片數據。這意味着只有分片的首選或備選worker才會緩存該分片的數據。

數據緩存📖

Alluxio文件系統是一個經常用作Presto分佈式緩存服務的開源數據編排系統。為了在架構中實現亞秒級的查詢延遲,我們希望進一步降低Presto和Alluxio之間的通信開銷。因此, Alluxio和Presto的核心團隊進行合作, 從Alluxio服務中發展出一個單節點的嵌入式緩存庫。

具體而言,Presto worker通過標準的HDFS接口查詢位於同一個JVM內的Alluxio本地緩存。當緩存命中時,Alluxio本地緩存直接從本地磁盤讀取數據,並將緩存數據返回給Presto;否則,Alluxio將訪問遠端數據源,並將數據緩存在本地磁盤上,以便後續查詢。該緩存對Presto來説是完全透明的。一旦緩存出現問題(如本地磁盤發生故障),Presto還可以直接從遠端數據源讀取數據,該工作流程如下圖所示:
image.png

本地緩存的內部構成和配置

Alluxio數據緩存是位於Presto worker節點上的庫,它提供了一種與HDFS兼容的接口“AlluxioCachingFileSystem” ,作為Presto worker進行所有數據訪問操作的主要接口。Alluxio數據緩存包含的設計選項有:

基本緩存單元

根據Alluxio的經驗以及Meta團隊早期的實驗,以固定的數據塊大小來進行數據讀寫和清理是最有效的。為了減少元數據服務的存儲和服務壓力,Alluxio系統中默認的緩存數據塊大小為64MB。由於我們採用的Alluxio數據緩存只需要在本地管理數據和元數據,所以我們大大調低了緩存的粒度,把默認緩存粒度設置成大小為1MB的 “page(頁面)”。

緩存位置和層級

Alluxio本地緩存默認將數據緩存到本地文件系統。每個緩存page作為單獨的文件存儲在目錄下,目錄結構如下:<BASE_DIR>/LOCAL/1048576/<BUCKET>/<PAGE>

✓ BASE_DIR是緩存存儲的根目錄,可以通過Presto的配置項 “cache.base-directory ”來設置。
✓ LOCAL表示緩存存儲類型為LOCAL(本地)。Alluxio也支持RocksDB作為緩存存儲。
✓ 1048576:代表數據塊的大小為1MB。
✓ BUCKET作為各種頁面文件的bucket的目錄。之所以創建bucket是為了確保單一目錄下不會有太多的文件,否則可能會導致性能很差。
✓ PAGE代表以頁面ID命名的文件。在Presto中,ID是文件名的md5哈希值。

線程併發

每個Presto worker包含一組線程,每個線程執行不同的查詢任務,但共享同一塊數據緩存。因此,該Alluxio數據緩存需要具備跨線程的高併發度,以提供高吞吐量。也就是説,數據緩存需要允許多個線程併發地獲取同一個page,同時還能在清除緩存數據時確保線程安全。

緩存恢復

當worker啓動(或重啓)時,Alluxio本地緩存會嘗試複用已經存在於本地緩存目錄中的緩存數據。如果緩存目錄結構是兼容的,則會複用已緩存數據。

監控

Alluxio在執行各種緩存相關操作時,會輸出各種JMX指標。通過這些指標,系統管理員可以輕鬆地監控整個集羣的緩存使用情況。

基準測試📖

我們以運行在某個生產集羣上的查詢來進行基準測試,該集羣被當作測試集羣來使用。

查詢數:17320
集羣大小:600個節點
單節點最大緩存容量:460GB
清除策略:LRU

緩存數據塊大小:1MB, 意味着數據按1MB的大小讀取、存儲和清除。

查詢執行時間優化(單位:毫秒):
image.png

從表格中可以看出,查詢延遲有顯著改善,其中P50的查詢延遲降低了33%,P75降低了54%,P95降低了48%。

開銷節省

✓ Master分支執行過程的總數據讀取大小:582 TB
✓ 緩存分支執行過程的總數據讀取大小:251 TB

節省的掃描數據量:57%

緩存命中率

在實驗過程中,緩存命中率基本穩定地保持在較高的水平,多數時間維持在 0.9 和 1 之間。中間可能是由於新查詢掃描大量新數據的原因出現了一些下降。我們需要添加一些其他算法來防止出現訪問不太頻繁的數據塊相較於訪問頻繁的數據塊更容易被緩存的情況。

如何使用?📖

使用數據緩存前,我們要做的第一件事就是啓用軟親和調度策略,數據緩存不支持隨機節點調度策略。

要啓用軟親和調度策略,在coordinator 中需要進行如下配置:

 "hive.node-selection-strategy", "SOFT_AFFINITY”

要使用默認(隨機)節點調度策略,則設置如下:

"hive.node-selection-strategy", "NO_PREFERENCE”

要啓用Alluxio數據緩存,在worker節點採用如下配置:

✓ 啓用worker節點上的數據緩存=> "cache.enabled", "true"
✓ 將數據緩存類型設置為Alluxio=> "cache.type", "ALLUXIO"
✓ 設置緩存數據存儲的基本目錄(base directory) => "cache.base-directory", "file:///cache"
✓ 配置單個worker緩存所能使用的最大數據容量:"cache.alluxio.max-cache-size", "500GB"

其他有用的配置如下

Coordinator 配置(可用來配置忙碌worker的定義):

✓ 設置單任務最大待定分片數:node-scheduler.max-pending-splits-per-task
✓ 設置單節點最大分片數:node-scheduler.max-splits-per-node

Worker 配置:

✓ 啓用Alluxio緩存指標(默認:true): cache.alluxio.metrics-enabled
✓ Alluxio緩存指標的JMX類名(默認: alluxio.metrics.sink.JmxSink): cache.alluxio.metrics-enabled
✓ Alluxio緩存使用的指標域名:(默認: com.facebook.alluxio): cache.alluxio.metrics-domain
✓ Alluxio緩存是否要異步寫入緩存(默認: false): cache.alluxio.async-write-enabled
✓ Alluxio緩存是否要驗證已有的配置(默認: false): cache.alluxio.config-validation-enabled

Alluxio數據緩存為其緩存操作輸出各種JMX指標。點擊查看指標名稱的完整列表。

下一步工作📖

✓ 實現通過限速器(rate limiter)控制緩存寫入操作的速率,從而避免閃存耐久性問題;
✓ 實現語義感知緩存,提高緩存效率;
✓ 建立清理緩存目錄的機制,用於維護或重新啓動。
✓ 可執行“dry run”模式
✓ 能夠施加各種容量使用限制,例如單表緩存配額限制,單分區緩存配額限制或單模式緩存配額限制。
✓ 構建更強大的worker節點調度機制。
✓ 增加新的算法實現,防止出現訪問不太頻繁的數據塊相較於訪問頻繁的數據塊更容易被緩存的情況。
✓ 容錯性:目前,當集羣中的節點數量發生變化時,基於哈希的節點調度算法會出現問題。我們正在努力實現更魯棒的算法,如一致性哈希。
✓ 更好的負載均衡:當我們把其他因素如分片大小、節點資源等納入考量後,我們就能更好地定義“忙碌”節點,繼而在實現負載均衡方面做出更明智的決策。
✓ 親和性標準:目前,Presto集羣內的親和性粒度是文件級的。如果不能在該粒度標準下達到最佳性能,則需要調整我們的親和性標準,使其更加細粒度,並在負載均衡和良好的緩存命中率之間找到平衡點,從而實現更好的整體性能。
✓ 提高Alluxio緩存庫的資源利用率。

文章貢獻者:🧔

Meta:Rohit Jain, James Sun, Ke Wang, Shixuan Fan, Biswapesh Chattopadhyay, Baldeep Hira
Alluxio: Bin Fan, Calvin Jia, Haoyuan Li
原文內容發佈於:2020/6/16

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.