Presto 在位元組跳動的內部實踐與優化

油竊發表於2022-01-09

  在位元組跳動內部,Presto 主要支撐了 Ad-hoc 查詢、BI 視覺化分析、近實時查詢分析等場景,日查詢量接近 100 萬條。本文是位元組跳動資料平臺 Presto 團隊-軟體工程師常鵬飛在 PrestoCon 2021 大會上的分享整理。

  在位元組跳動內部,Presto 主要支撐了 Ad-hoc 查詢、BI 視覺化分析、近實時查詢分析等場景,日查詢量接近 100 萬條。

  • 功能性方面:完全相容 SparkSQL 語法,可以實現使用者從 SparkSQL 到 Presto 的無感遷移;

  • 效能方面:實現 Join Reorder,Runtime Filter 等優化,在 TPCDS1T 資料集上效能相對社群版本提升 80.5%;

  • 穩定性方面:首先,實現了多 Coordinator 架構,解決了 Presto 叢集單 Coordinator 沒有容災能力的問題,將容災恢復時間控制在 3s 以內;其次實現了基於 histogram 的靜態規則和基於執行時狀態的動態規則,可以有效進行叢集的路由和限流;

  • 可運維性方面:實現了 History Server 功能,可以支援實時追蹤單個 Query 的執行情況,總體觀察叢集的執行狀況。

  位元組跳動 OLAP 資料引擎平臺 Presto 部署使用情況

  過去幾年,位元組跳動的 OLAP 資料引擎經歷了百花齊放到逐漸收斂,再到領域細分精細化運營優化的過程。

  儲存方面離線資料主要儲存在 HDFS,業務資料以及線上日誌類資料儲存在 MQ 和 Kafka。

  計算引擎根據業務型別不同,Presto 支撐了 Ad-hoc 查詢、部分 BI 報表類查詢,SparkSQL 負責超大體量複雜分析及離線 ETL、Flink 負責流式資料清洗與匯入。

  為了處理日益增長的 Ad-hoc 查詢需求,在 2020 年,位元組跳動資料平臺引入 Presto 來支援該類場景。

  目前,整個 Presto 叢集規模在幾萬 core,支撐了每天約 100 萬次的查詢請求,覆蓋了絕大部分的 Ad-hoc 查詢場景以及部分 BI 查詢分析場景。  圖注:位元組跳動內部 Presto 叢集部署架構圖

  上圖是位元組跳動內部 Presto 叢集部署的架構,針對不同的業務需求拆分為了多個相互隔離的叢集,每個叢集部署多個 Coordinator,負責排程對應叢集的 Worker。

  接入層提供了統一的 Gateway,用以負責使用者請求的路由與限流。同時還提供了 History Server,Monitor System 等附屬元件來增加叢集的可運維性與穩定性。

  Presto 叢集穩定性和效能提升

  針對不同的業務場景以及查詢效能要求,我們將計算資源拆分為了相互獨立的 Presto 叢集。  Gateway 負責處理使用者請求的路由,這部分功能主要通過靜態的路由規則來實現,路由規則主要包括允許使用者提交的叢集以及降級容災的叢集等。

  為了更好的平衡不同叢集之間的負載情況,充分有效的利用計算資源,後期又引入了動態的路由分流策略。該策略在做路由選擇的過程中會呼叫各個叢集 Coordinator 的 Restful API 獲取各個叢集的負載情況,選擇最優的叢集進行路由排程。

  通過靜態規則與動態策略相結合的方式,Gateway 在為使用者提供統一接入介面的情況下,也保證了叢集之間工作負載的平衡。  Coordinator 節點是單個 Presto 叢集的核心節點,負責整個叢集查詢的接入與分發,因此它的穩定性直接影響到整個叢集的穩定性。

  在最初的部署中,每個 Presto 叢集只能部署一個 Coordinator,當該節點崩潰的時候,整個叢集大概會消耗幾分鐘的不可用時間來等待該節點的自動拉起。

  為了解決這個問題,我們開發了多 Coordinator 的功能。該功能支援在同一個 Presto 叢集中部署多個 Coordinator 節點,這些節點相互之間處於 active-active 備份的狀態。

  主要實現思路是將 Coordinator 和 Worker 的服務發現使用 Zookeeper 來進行改造。

  Worker 會從 Zookeeper 獲取到現存的 Coordinator 並隨機選取一個進行心跳上報,同時每個 Coordinator 也可以從 Zookeeper 感知到其他 Coordinator 的存在。

  每個 Coordinator 負責儲存當前連線到的 Worker 的任務負載情況以及由它排程的查詢執行情況,同時以 Restful API 的形式將這些資訊暴露出去;其他 Coordinator 在做任務排程的時候會通過這些 Restful API 獲取到整個叢集的資源使用情況進行相應的任務排程。

  目前多 Coordinator 機制已經在叢集中上線使用了半年,將叢集的不可用時間從幾分鐘降低到 3s 以內。  另一個影響 Presto 叢集穩定性的重要因素是超大規模的查詢。

  在 Ad-hoc 場景下,這種查詢是無法避免的,並且由於這種查詢會掃描非常多的資料或者生成巨大的中間狀態,從而長期佔用叢集的計算資源,導致整個叢集效能下降。

  為了解決這個問題,我們首先引入了基於規則以及代價的查詢時間預測。

  > 基於規則的查詢時間預測主要會統計查詢涉及到的輸入資料量以及查詢的複雜程度來進行預測。

  > 基於代價的查詢時間預測主要是通過收集在 Catalog 中的 Histogram 資料來對查詢的代價進行預測。

  上述預測能夠解決部分問題,但是還是會存在一些預估不準的情況,為了進一步處理這些情況,我們引入了 Adaptive Cancel 功能。

  該功能主要是在查詢開始執行後,週期性的統計查詢預計讀取的資料量以及已完成的任務執行時間來預測查詢整體的執行時間,對於預測超過閾值的查詢提前進行取消,從而避免計算資源浪費,提升叢集穩定性。  另外,Presto 本身提供的 UI 介面可以很好地對查詢執行情況進行分析,但是由於這部分資訊是儲存在 Coordinator 記憶體當中,因此會隨著查詢數量的累積而逐步清除,從而導致歷史查詢情況無法獲取。

  為了解決這個問題,我們開發了 History Server 的功能。

  Coordinator 在查詢執行完成之後會將查詢的執行情況儲存到一個持久化儲存當中,History Server 會從持久化儲存當中載入歷史的查詢執行情況並提供與 Presto UI 完全相同的分析體驗,同時基於這部分持久化的資訊,也可以建立相應的監控看板來觀測叢集的服務情況。

  三個場景優化的實踐分享

  Ad-hoc 查詢分析場景

  2020 年之前,大資料場景下的 Ad-hoc 查詢主要由 Hive/SparkSQL 來支撐。為了進一步優化查詢效能,提高資源使用效率,從 2020 年開始,我們在生產環境大規模使用 Presto。

  • 與 SparkSQL 相比,Presto 是一個常駐的 MPP 架構的 SQL 查詢引擎,避免了 Spark Context 啟動以及資源申請的開銷,端到端延遲較低。

  • 與 Hive/Spark Thrift Server 相比,Presto Coordinator 更加成熟,輕量,穩定,同時 Presto 基於全記憶體的 Shuffle 模型可以有效的降低查詢延遲。

  為了做到使用者查詢無感遷移到 Presto,我們做了大量的工作使得 Presto 在語法和語義層面相容 SparkSQL。  • 在接入層方面:提供了 SQL 標準化改寫功能。該功能可以將使用者的 SQL 改寫成 Presto 可以支援的 SQL 語法進行執行,做到了底層引擎對使用者透明。

  • 在函式支援方面:在 Presto 中支援了 Hive UDF 的執行,使得之前資料分析師積累下來的大量 UDF 可以在 Presto 中執行。該功能主要支援了在解析階段可以載入 Hive UDF 和 UDAF,並進行型別轉換使其適配 Presto 型別體系,最終封裝成 Presto 內建函式的形式進行執行。目前該功能部分已經貢獻回了 Presto 社群。社群地址

  BI 視覺化分析場景

  Presto 在位元組跳動應用的另一個比較重要的場景是 BI 視覺化分析。

  BI 視覺化分析提供了視覺化互動的功能來進行資料分析,資料分析可以直觀快速的進行資料分析並生成相應的分析圖表,這給查詢引擎提出了更高的要求。在這一場景下,不僅,QPS 大幅提高,同時還要求查詢引擎能給出比較低的查詢延遲。

  為了應對這些挑戰,我們做了一個比較重要的工作——在 Presto 中引入了物化檢視。

  這種場景下,查詢 SQL 往往都是由 BI 視覺化平臺根據固定的模版自動生成的,使用者的視覺化操作往往限於對查詢過濾條件,聚合維度以及聚合指標的改變,適合物化檢視的應用。  在物化檢視功能中,我們借鑑了很多傳統資料庫的經驗,工作主要涉及三方面的工作:

  • 物化檢視的自動挖掘——主要根據使用者查詢的歷史記錄進行分析,統計不同資料的查詢頻率進行物化檢視的自動推薦與建立。

  • 物化檢視的生命週期管理——主要維護分割槽級別物化檢視的自動更新,刪除。

  • 物化檢視的重寫功能——基於已有的物化檢視,對使用者的 query 進行重寫以減少查詢執行的複雜度。  近實時場景的查詢分析

  這是今年開始探索的一個場景,主要是為了降低資料鏈路的延遲,提升查詢分析的時效性。

  傳統的基於 ETL 的資料鏈路中,業務資料和日誌資料經由 Kafka 定期 dump 到 HDFS,然後會有多個 ETL 任務對資料進行加工清理形成不同層級的 Hive 表用來進行查詢分析。

  這個鏈路中往往需要進行表資料的全量更新,任務比較重,與線上資料存在 1 天以上的資料延遲。

  為了降低資料延遲,我們引入了 Hudi 來進行資料的增量更新。

  在這個鏈路中,業務資料和日誌資料經由 Spark/Flink Streaming 任務增量寫入到 Hudi 表中,資料分析師可以直接查詢這部分資料。目前,該鏈路可以做到分鐘級別的資料延遲。

  我們在 Presto 的優化工作主要是將 Hudi 表讀取的功能從 Hive Connector 中提取出來成為了一個單獨的 Hudi Connector。 • 首先,Hudi Connector 針對 Hudi 表的結構特點更好地支援了基於不同策略的分片排程演算法,保證任務分配的合理性。

  • 同時,Hudi Connector 優化了 Hudi MOR 表讀取過程中的記憶體管理,避免了 Worker 節點 OOM,提升了叢集穩定性。

  • 最後,Hudi Connector 的引入降低了 Hudi 版本升級帶來的工作量,可以更好的整合 Hudi 社群最新的功能。這部分功能我們將會逐步貢獻回社群。社群地址

  本文中介紹的位元組跳動內部 Presto 功能優化,目前已通過火山引擎資料產品“湖倉一體分析服務”向外部企業輸出。**湖倉一體分析服務 LAS(Lakehouse Analytics Service)**是面向湖倉一體架構的 Serverless 資料處理分析服務,提供一站式的海量資料儲存計算和互動分析能力,完全相容 Spark、Presto、Flink 生態,幫助企業輕鬆完成資料價值洞察。


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

相關文章