攜程 Spark 多租戶查詢服務演進,Apache Kyuubi 未來可期

語言: CN / TW / HK

當我們開始把大多數在 Hive 的查詢和 ETL 作業遷移到 Spark,面臨的幾個問題是如何透明遷移 HiveServer2 服務以及如何保證穩定性。

與 HiveServer2 對應的 Spark Thrift Server 是 Apache Spark 社群基於 HiveServer2 實現的一個 Thrift 服務,目標是做到無縫相容 HiveServer2。與 HiveServer2 類似,通過 JDBC 介面提交 SQL 到 Thrift Server。

1 原生的 Spark Thrift Server

1.1 執行方式

通過./sbin/start-thriftserver.sh啟動 Spark Thrift Server,它不僅僅包含了一個 Spark Driver,還提供了一個基於 Thrfit 協議的服務。

在 Servier 通過 SparkSQLSessionManager 管理所有 Client 對應的 Session,使用 JDBC 連線 Server 時,Server 使用 SparkSession.newSession 建立了一個隔離的 Session。

在 Server 通過 SparkSQLOperationManager 管理所有 Operation,之後 Client 提交每一條 SQL ,作為一次 Operation ,Server 通過 Client 繫結的 Session 使用 SparkSession.sql API 提交 SQL。

Server(Driver) 負責編譯優化 SQL,生成 Job,提交到 Executor 執行,非同步等待完成。

Client 輪詢 Server SQL 是否完成,並拉取結果。

1.2侷限

相比於 HiveServer2,Spark Thrift Server是比較脆弱的。

一般來說,Spark Driver 比 Hive Driver 更為繁忙一點。Hive 編譯優化 SQL,提交 MapReduce Job,輪詢結果,而 Spark Driver 不僅僅要做 Hive 的類似事情,還需要管理資源排程,增加和減少 Executors,排程 Job、Task 執行,廣播變數、小表,這也導致了 Spark Driver更容易有 OOM 的問題,當這個問題出現在 Driver 與 Server 繫結的同個程序中,問題就更為嚴峻,可能導致多個 Client 突然失敗。

2 Trip-Spark2 多租戶

基於上述原生 Spark Thrift Server 不能夠滿足需求,我們基於 Spark2 擴充套件了一些實現。

2.1 執行方式

在 Client 發起 openSession 時, Server 在 SparkSQLSessionManager.openSession 對當前的 Session User 申請 HDFS DelegationTokens 和 Hive DelegationTokens。這一塊 Token 傳遞和重新整理和Spark2 Streaming 更新 Token 邏輯類似。

在 DAGScheduler submit job 的時候關聯 SQL,JobId,User 資訊,並繫結到 Task。

在 Executor 使用 Task 對應的 UGI doAs 執行。

由於 Spark2 還有多處的實現用到了執行緒池,這裡也需要模擬成不同的使用者去執行。

2.2 實現功能

  • 支援多租戶

    支援多個 UGI 使用者連到同一個 Server,並以不同的使用者身份來連線 Hive Meta Store,執行 DDL,執行 Task

  • 基於 Zookeeper 實現 High Availability

  • 在 operationLog 實現查詢進度條

  • 支援只有 SELECT 型別才返回 ResultSet

  • 針對 Ad-Hoc,報表場景對 SQL 自動增加 Limit

  • Limit 初始分割槽數可配置

    加 Limit 之後,初化分割槽數預設從 1 開始,有時候提交多次 Job 才符合 Limit 條數

    https://issues.apache.org/jira/browse/SPARK-37605

  • 支援 Graceful stop

    下線某臺 Server,Client 無感知,不會報錯

  • 支援 YARN Cluster

    原生的只支援 YARN Client 模式部署,支援 Cluster 可以更好利用 YARN 資源

  • 持 一個使用者 多個 HiveCatalog

    有時候一個 Session 執行的 SQL 可能會導致單個 HiveCatalog 卡住,導致其它 Session 可能只是簡單的 DDL、DML 響應比較慢

  • 使用 STS 過程了也遇到一些問題並修復

    [SPARK-26992][STS] Fix STS scheduler pool correct delivery

    https://issues.apache.org/jira/browse/SPARK-26992

    [SPARK-26598][SQL] Fix HiveThriftServer2 cannot be modified hiveconf/hivevar variables

    https://issues.apache.org/jira/browse/SPARK-26598

  • ...

2.3 侷限

1. 在 YARN 層面 App 對應的使用者是超級使用者,不能細粒度劃分資源

2. Spark Jars、Files 是全域性共享的,這導致了 UDF 隔離性不是很好

3. 擴充套件特性對 Spark Core 、SQL、ThriftServer 模組改動較多,與 Spark 版本深度繫結

Kyuubi-Spark3 多租戶

當我們開始從 Spark2 遷移到 Spark3 的時候,開始調研 Apache Kyuubi,決定用來替換 Spark2 Thrift Server。

目前已經上線大半年,從早期的 1.3,1.4 到現在 1.5 版本,承接原先 Spark2 80% 查詢量。

在早期調研和灰度上線,發現了一些問題,修復之後也回饋了社群。

  • Engine 閒置退出還會重試提交,導致 Engine 沒有釋放

  • 簡化客戶端連線串,方便遷移 HiveServer2 應用(kyuubi.ha.zookeeper.publish.configs)

  • 自動加 Limit 的 Rule 資料不準確

  • 開啟超時 Query 自動 Kill 能相容低版本 JDBC Client

  • ...

另外也基於原先 Spark2 二次開發的一些特性,對 Kyuubi 做了一些改造。

3.1 執行方式

Apache Kyuubi 的架構分為兩層,一層是Server 層,一層是Engine 層。

Server 層和 Engine 層都有一個服務發現層,KyuubiServer 層的服務發現層用於隨機選擇一個 Kyuubi Server,Kyuubi Server 對於所有使用者來共享的。

Kyuubi Engine 層的服務發現層對使用者來說是不可見的。它是用於 Kyuubi Server 去選擇對應的使用者的 Spark Engine,當一條使用者的請求進來之後,它會隨機選擇一個 Kyuubi Server,Kyuubi Server 會去 Engine 的服務發現層選擇一個 Engine。如果 Engine 不存在,它就會建立一個 Spark Engine,這個 Engine 啟動之後會向 Engine 的服務發現層去註冊,然後 Kyuubi Server 和 Engine 之間的再進行一個內部連線。所以說 Kyuubi Server 是所有使用者共享,Kyuubi Engine 是使用者之間資源隔離。

3.2 優點

  1. 設計上天然多租戶,支援Cluster 模式

  2. 不與 Spark 具體版本繫結,支援 N 個大小 Spark3 版本

  3. 隔離性好,支援資源佇列隔離,Engine 隔離

    可以按代理使用者提交到使用者的 YARN 資源佇列,通過指定kyuubi.engine.share.level,kyuubi.engine.share.level.subdomain 還可以實現 Engine 隔離

  4. Engine 支援 Long Running,Server 管理所有使用者 Token 更為優雅

  5. 使用 Explain 模式,可以預解析 SQL

    通過設定 kyuubi.operation.plan.only.mode ,可以把通過 Lineage Plugin 收集的 Spark2 所有 SQL ,使用 JDBC 提交到 Kyuubi 進行解析 ,對升級 Spark 版本檢查 SQL 語法相容性有很大的幫助

  6. 自帶不少基於 Spark 的優化規則,通過 SparkSessionExtensions 注入

  7. 通過 kyuubi-ctl 實現 Server、Engine graceful stop

    升級 Kyuubi 或者 Spark 版本,使用 kyuubi-ctl 下線 Server、Engine 節點,終端使用者無感知

  8. 可以按不同的使用者進行個性配置

    使用 ___{username}___.{config key} 可以很方便對每個使用者進行個性化的配置,還支援使用 SessionConfAdvisor Plugin 動態覆蓋配置。

3.3 侷限

現在 Kyuubi 使用 kyuubi.engine.share.level 配置項,用來控制 Engine 不同場景的隔離級別。

  • CONNECTION

    每次建立連線都會啟動一個 Engine,不共享,連線斷開,銷燬 Engine,適合 ETL 或者隔離性要求較高的任務。

  • USER

    預設值,同一個使用者會共享同一個 Engine,不同的連線關閉後 Engine 不會銷燬,通過kyuubi.session.engine.idle.timeout配置來控制 Engine 閒置多久後自動銷燬,常用於 Ad-Hoc,報表查詢場景。

  • GROUP

    使用連線使用者對應的 Group(Hadoop Groups Mapping)建立 Engine,屬於同個 Group 可以共享同個 Engine。

  • SERVER

    使用啟動 Kyuubi Server 的使用者建立 Engine,每個連線都可以共享同個 Engine。

我們常用的模式是 USER,當我們有很多不同的使用者的時候,會建立不少 Engine,第一次 Engine 建立和啟動會相對慢一些。

並且使用kyuubi.engine.pool.size來控制每個 USER 能建立幾個 Engine,由於目前社群版本使用隨機演算法來選擇 Engine,當 pool size 設定比較大,可能會建立不少 Engine,有時候每個 Engine 的負載並不高。

目前這一塊社群計劃優化中。

以上是根據基於內部使用場景的一些簡單的概括對比,Apache Kyuubi 社群還有更詳細的比較:

https://kyuubi.readthedocs.io/en/latest/overview/kyuubi_vs_thriftserver.html

展望

Apache Kyuubi 專案的目標是 建立在企業級即席 SQL 查詢服務,基本上做到了開箱即用,同時也帶來了不少實用的 Spark 引擎擴充套件,一些 watchdog 實現,限制查詢的分割槽數,限制查詢的結果數,此外還有小檔案合併,Z-Order 等強大功能。

最新Release 1.5.2版本 已支援 Spark SQL,Flink SQL,Trino,還支援 Scala 程式碼片段提交。

在未來 1.6 版本還支援 Hive Engine,提交 Jar 任務,Spark 支援 Ranger 鑑權外掛,TPC-DS 、TPC-H Connector,未來可期!

作者簡介: 陳少雲,攜程大資料平臺開發專家,Apache Kyuubi(Incubating) Committer,負責大資料離線平臺的開發和維護工作,關注大資料領域生態建設。