看SparkSql如何支撐企業數倉

abstractcyj發表於2022-02-23

企業級數倉架構設計與選型的時候需要從開發的便利性、生態、解耦程度、效能、 安全這幾個緯度思考。本文作者:驚帆 來自於資料平臺 EMR 團隊

前言

Apache Hive 經過多年的發展,目前基本已經成了業界構建超大規模資料倉儲的事實標準和資料處理工具,Hive 已經不單單是一個技術元件,而是一種設計理念。Hive 有 JDBC 客戶端,支援標準 JDBC 介面訪問的 HiveServer2 伺服器,管理後設資料服務的 Hive Metastore,以及任務以 MapReduce 分散式任務執行在 YARN 上。

標準的 JDBC 介面,標準的 SQL 伺服器,分散式任務執行,以及後設資料中心,這一系列組合讓 Hive 完整的具備了構建一個企業級資料倉儲的所有特性,並且 Hive 的 SQL 伺服器是目前使用最廣泛的標準伺服器。

雖然 Hive 有非常明顯的優點,可以找出完全替代 Hive 的元件寥寥無幾,但是並不等於 Hive 在目前階段是一個完全滿足企業業務要求的元件,很多時候選擇 Hive 出發點並不是因為 Hive 很好的支援了企業需求,單單是因為暫時找不到一個能支撐企業訴求的替代服務。

企業級數倉構建需求

數倉架構通常是一個企業資料分析的起點,在數倉之下會再有一層資料湖,用來做異構資料的儲存以及資料的冷備份。但是也有很多企業,特別是幾乎完全以結構化資料為主的企業在實施上會把資料湖和企業數倉庫合併,基於某個數倉平臺合二為一。

企業在考慮構建自身數倉體系的時候,雖然需要參考現有的行業技術體系,以及可以選擇的元件服務,但是不能太過於侷限於元件本身,尋找 100%開箱即用的產品。太過於侷限於尋找完全契合的元件服務必然受限於服務本身的實現,給未來擴充套件留下巨大的約束。企業資料倉儲架構必然不等於一個元件,大部分企業在數倉架構實施的都是都是基於現有的部分方案,進行基於自己業務合適的方向進行部分開發與定製,從而達到一個半自研的穩態,既能跟上業務變化的速度,又不過於依賴和受限於元件自身的發展。

一般來說企業級數倉架構設計與選型的時候需要從以下幾個緯度思考:

  • 開發的便利性:所選擇的數倉架構是否具有很好的開發生態,可以提供不同型別的開發態介面,不限於 SQL 編輯器,程式碼提交,以及第三方工具整合。

  • 生態:所選擇實現引擎自身是否有很好的生態功能,或者是否可以很好的與其他服務整合,例如資料湖引擎 delta lake,icebeg,hudi 等優秀元件出現,但是 Hive 整合的節奏卻非常慢。

  • 解耦程度:分散式任務必然需要多個元件的協調,例如分散式儲存,資源管理,排程等,像 Hive 就重度依賴於 YARN 體系,計算引擎也與 MR 強繫結,在解耦方面較弱,如果企業考慮在 K8S 上構建自己的計算引擎,Hive 面臨的侷限會更加明顯。

  • 效能:整體架構是否擁有更好的效能。

  • 安全:是否支援不同級別,不同力度的使用者訪問和資料安全鑑權體系。

對於企業數倉架構來說,最重要的是如何基於企業業務流程來設計架構,而不是基於某個元件來擴充套件架構。

一個企業數倉的整體邏輯如上圖所示,數倉在構建的時候通常需要 ETL 處理和分層設計,基於業務系統採集的結構化和非結構化資料進行各種 ETL 處理成為 DWD 層,再基於 DWD 層設計上層的資料模型層,形成 DM,中間會有 DWB/DWS 作為部分中間過程資料。

從技術選型來說,從資料來源的 ETL 到資料模型的構建通常需要長時任務,也就是整個任務的執行時間通常是小時及以上級別。而 DM 層主要是支援業務的需求,對實效性要求比較高,通常執行在 DM 層上的任務時間在分鐘作為單位。

基於如上的分層設計的架構圖可以發現,雖然目前有非常多的元件,像 Presto,Doris,ClickHouse,Hive 等等,但是這些元件各自工作在不同的場景下,像數倉構建和互動式分析就是兩個典型的場景。

互動式分析強調的是時效性,一個查詢可以快速出結果,像 Presto,Doris,ClickHouse 雖然也可以處理海量資料,甚至達到 PB 及以上,但是主要還是是用在互動式分析上,也就是基於資料倉儲的 DM 層,給使用者提供基於業務的互動式分析查詢,方便使用者快速進行探索。由於這類引擎更聚焦在互動式分析上,因此對於長時任務的支援度並不友好,為了達到快速獲取計算結果,這類引擎重度依賴記憶體資源,需要給這類服務配置很高的硬體資源,這類元件通常有著如下約束:

  • 沒有任務級的重試,失敗了只能重跑 Query,代價較高。

  • 一般全記憶體計算,無 shuffle 或 shuffle 不落盤,無法執行海量資料。

  • 架構為了查詢速度快,執行前已經排程好了 task 執行的節點,節點故障無法重新排程。

一旦發生任務異常,例如網路抖動引起的任務失敗,機器當機引起的節點丟失,再次重試所消耗的時間幾乎等於全新重新提交一個任務,在分散式任務的背景下,任務執行的時間越長,出現錯誤的概率越高,對於此類元件的使用業界最佳實踐的建議也是不超過 30 分鐘左右的查詢使用這類引擎是比較合適的。

而在離線數倉場景下,幾乎所有任務都是長時任務,也就是任務執行時常在小時及以上,這時就要求執行 ETL 和構建數倉模型的元件服務需要具有較高的容錯性和穩定性,當任務發生錯誤的時候可以以低成本的方式快速恢復,儘可能避免因為部分節點狀態異常導致整個任務完全失敗。

可以發現在這樣的訴求下類似於 Presto,Doris,ClickHouse 就很難滿足這樣的要求,而像 Hive,Spark 這類計算引擎依託於 Yarn 做資源管理,對於分散式任務的重試,排程,切換有著非常可靠的保證。Hive,Spark 等元件自身基於可重算的資料落盤機制,確保某個節點出現故障或者部分任務失敗後可以快速進行恢復。資料儲存於 HDFS 等分散式儲存系統上,自身不管理資料,具有極高的穩定性和容錯處理機制。

反過來,因為 Hive,Spark 更善於處理這類批處理的長時任務,因此這類元件不擅長與上層的互動式分析,對於這種對於時效性要求更高的場景,都不能很好的滿足。所以在考慮構建數倉的時候,通常會選擇 Hive,Spark 等元件來負責,而在上層提供互動式分析查詢的時候,通常會使用 Presto,Doris,ClickHouse 等元件。

歸納下來如下:

  • Presto,Doris,ClickHouse:更注重互動式分析,對單機資源配置要求很高,重度依賴記憶體,缺乏容錯恢復,任務重試等機制,適合於 30 分鐘以內的任務,通常工作在企業的 DM 層直接面向業務,處理業務需求。

  • Hive,Spark:更注重任務的穩定性,對網路,IO 要求比較高,有著完善的中間臨時檔案落盤,節點任務失敗的重試恢復,更加合適小時及以上的長時任務執行,工作在企業的的 ETL 和資料模型構建層,負責清洗和加工上層業務所需要的資料,用來支撐整個企業的數倉構建。

一個企業在實施資料平臺的時候,由多個不同元件各自工作在不同的架構層中,無法相互取代,相互協作配合,承載整個企業的資料平臺業務。

企業級數倉技術選擇

Google 發表的三篇論文從儲存,計算,檢索三個方向闡述了海量資料下一種新的分散式資料加工處理技術,這三個方向被雅虎 Nutch 團隊實現後貢獻給 Apache,也就是目前大家看到的 HDFS,MapReduce 和 HBase,形成了早期 Hadoop 的三大利器。

然而這三大利器更聚焦在異構資料的資訊提取處理上,沒有提供對結構化資料很友好的類似 SQL 語法的分析入口,同時在程式設計態的支撐也不夠友好,只有 Map 和 Reduce 兩階段,嚴重限制了業務處理的實現,雅虎團隊也是爬蟲相關業務孵化而出,可以看出 Hadoop 早期的三大套件有著如下特點:

  • 門檻高,需要程式設計實現,並且程式設計態受限於 MapReduce 的兩階段約束。

  • 以離散資料處理為主,對分析能力,查詢等常用資料分析功能支援不足。

  • 沒有互動式客戶端,無法實現互動式探索。

Hive 就是誕生在這樣的較大的行業背景下,Hive 的出現剛好彌補了 Hadoop 只能用來做離線資料處理這個缺陷,提供了一種常用的分析介面,並且提供了非常好的使用者互動方式。

Hive 整體架構如上圖所示(本圖來自於 Hive 官網),Hive 提供 JDBC 介面實現支援以程式設計形式進行互動,同時業內幾乎所有 SQL Client、開源或商業 BI 工具都支援通過標準 JDBC 的方式連線 Hive,可以支援資料探索的動作,極大的豐富了大資料生態圈下的元件多樣性,同時也降低了使用門檻,可以讓熟悉 SQL 的人員低成本遷移。

基於這些設計非常好的特效,加上 Hive 經過這多年的逐步完善,發展到今天已經是一個非常穩定成熟的生產環境可用的資料倉儲元件,甚至替代品都很難找到,因此使用 Hive 作為資料倉儲的構建基礎是一個非常好的選擇。

如上圖所示,其中有很多優點:

  • 穩定:穩定性是 Hive 一個非常讓人稱道的特性,很多時候雖然 Hive 的效能,計算速度不及其他引擎,但是 Hive 的穩定性卻一直是非常好的。

  • 低門檻:只需要掌握基本的 SQL 技能,便可使用 Hive 進行開發,相比其他分散式計算引擎引擎成本更低。

  • 生態豐富:Hive 和 Hadoop 生態圈緊密結合,而 Hive 自身的 Metastore 也成了大資料生態圈內的標準後設資料服務,大部分引擎都支援直接適配 MetaStore。

  • 擴充套件方便:Hive 自身的 UDF 機制可以快速基於業務需要擴充套件功能。

  • 安全:Hive 支援 Kerberos/LDAP 多種認證方式,並且和 Ranger 結合可以做到更細粒度的行列許可權級別,擁有較好的資料安全。

  • 整合成本低:MapReduce 只支援程式設計態的介面,並且不支援迭代計算,Hive 封裝了 MapReduce 提供 SQL 的介面,可以很低成本的和上層資料探勘,資料分析工具進行整合。

所以雖然 Hive 出現已經非常有很長時間了,但是依舊是數倉構建的首選,在整個數倉構建中隨處可見 Hive 的身影。雖然 Hive 有種種優點,讓人難以割捨,但是並不等於能很好的支撐企業業務需求。很多時候選擇 Hive 僅僅是因為暫時沒有其他可選的元件,如果自己從頭開發一個,或者基於某個元件改造,成本又會遠超企業預期,因此不得不繼續選擇使用 Hive。

基於實踐來看,Hive 在構建企業數倉過程中存在的主要侷限圍繞在以下幾個方面:

  • 效能:Hive 基於 MapReduce 雖然帶來了非常好的穩定性,同時也降低了它的效能,雖然有 TEZ 做一定的優化,但是與同類的計算引擎 Spark 相比依舊有非常大的差距。

  • 資源配置:由於 Hive 底層使用 MapReduce 作為計算引擎,而 MapReduce 對 SQL 不友好,因此 Hive 在 HiveServer2 層面實現了 SQL 的轉換處理,再生成基於 MapReduce 的物理計劃,從而導致 HiveServer2 需要非常高的配置,才能維持足夠好的穩定性。

  • 併發:Hive 的併發受限於 HiveServer2,企業需要維護多個高配的 HiveServer2 例項才能支援更好的並非,通常 Hive 的瓶頸都在 HiveServer2 而不是更底層的分散式計算。

  • 容錯成本:Hive 基於 HiveServer2 進行 SQL 的分析處理,多個 HiveServer2 之間相互獨立不共享資訊,因此當 HiveServer2 掛掉後,整個 HiveServer2 的任務都會結束,需要客戶端自行重試,為整個作業級別的容錯重啟。

  • 事務支援:Hive 的事務設定在 HiveServer2 上,一旦 HiveServer2 例項開啟事務後,整個通過該 HiveServer2 的請求都會開啟事務,整個事務成本過高。

  • 部署:如果企業的計算引擎部署是基於 K8S 等容器架構,Hive on K8S 將會帶來非常大的部署成本。

雖然 Hive 在以上侷限層面也做了很多嘗試,Hive On Spark,但是受限於 Hive 的架構,HiveServer2 自身有自己的 SQL 解析引擎,為了相容架構將解析後的結果直接翻譯成 Spark 最底層的介面,整體效能反而提升不大。

除了 Hive 之外,還有非常多的其他優秀的元件,但是從企業數倉技術選型的視角來看,適合用來構建資料倉儲的,目前只有 Hive 和 Spark SQL 相對更加合適,在這兩個元件中,Spark SQL 相對 Hive 的優勢又更加明顯。

SparkSQL 如何支撐企業級數倉

Spark 引擎因為自身強大的生態和方便的程式設計介面被廣泛應用在資料處理場景下,Spark 提供的 Spark SQL 模組更是將使用 Spark 支撐企業資料倉儲提供了一個良好的基礎設施。

如上圖所示,一個典型的資料倉儲架構需要包含不同層次的模型構建。由於資料量大,資料結構異構等多種原因,大資料架構下的企業數倉構建拋棄了基於關係型資料庫下的 Cube 設計,直接採用基於分散式任務進行處理來構建多層資料模型。因此對於構建企業數倉的服務來說,有著如下要求:

  • 支援長時任務,通常是小時以上,天級別居多。

  • 支援多工,也就是高併發。

  • 穩定性必須被保障。

  • 速度快。

  • 支援 SQL 的互動式介面。

  • 易於整合。

  • 支援任務的重跑和容錯以及快速任務失敗恢復。

基於以上特性可以發現,在目前可選擇的元件範圍內,Spark SQL 相比其他元件,乃至 Hive 更加合適承擔這類任務。但是很多企業在進行架構設計的時候割捨不掉 Spark SQL 帶來的豐富特性,又愁於 Spark SQL 缺乏類似 Hive 這樣的 SQL 伺服器,於是退而求其次變成 Hive 與 Spark SQL 兩個元件共存的形態,Hive 退化為僅僅提供 MetaStore 服務,因此從很多實踐的現象來看,Hive 構建企業數倉已是過去式,採用 Spark SQL 進行資料倉儲的構建是眾多的選擇。

如上圖所示,企業在構建數倉的時候,通過一個 Spark SQL Server 提供基於 SQL 介面的常駐服務,同時也可以採用 Spark Submit 的方式直接提交 Jar 任務去執行,既能達到提供標準 SQL 互動式介面,又能提供更靈活的程式設計態介面。

從不同的企業級數倉構建視角來看,Hive 帶來的約束都越來越大,而 Spark SQL 的成熟度和發展趨勢已經完全具備取代 Hive 來構建整個數倉,Spark SQL 的優勢集中體現在如下方面:

  • 豐富的生態:Spark 不僅可以和很多元件整合,其自身擁有生態已經涵蓋各個方面,從資料分析到機器學習和圖計算。

  • 開放:Spark 架構設計上非常開放,可以快速整合其他產品,例如相比 Hive,在整合 Iceberg,Hudi 等特性方面就會開放很多。

  • 部署:Spark 既可以部署在 ECS 虛擬機器上,也可部署在 K8S 架構上,多種部署形態非常靈活。

  • 效能:Spark 的機制的流批處理效能非常合適用來構建企業數倉。

  • 易於開發:Spark SQL 既有 SQL 介面,也支援靈活的可迭代程式設計介面,非常方便不同場景下的資料開發。

  • 安全:Spark SQL 可和不同的安全服務整合,實現細粒度的鑑權。

因此,完全基於使用 Spark SQL 來支撐企業級的數倉是完全可行的,並且在目前也被眾多企業實踐驗證。

如上圖所示,一個基於 Spark SQL 構建的企業數倉架構邏輯架構設計上包含以上幾個部分,每一個 Spark SQL 引擎都是一個伺服器,Spark SQL 引擎將自己的資訊註冊到 Zookeeper 中,SQL 伺服器基於 Zookeeper 中的 Spark SQL 引擎來執行客戶端過來的請求,SQL 伺服器是一個相容 Hive JDBC 介面的伺服器,在使用 Spark SQL 來支撐數倉構建的時需要重點考慮的實施點是:

  • 如何提供一個互動服務用來支撐不同的客戶端來連線,包括互動式的 beeline,以及程式設計態的 JDBC 和工具介面。

  • 如何打通許可權對接,如果是 Ranger 的話需要的是 Spark SQL Ranger Plugin。

  • 如何支援跨多個佇列的任務提交。

使用 Spark SQL 支撐企業級數倉的核心的地方還是在於如何提供一個好用的任務伺服器,用來支撐任務的管理。任務管理伺服器在邏輯上與 HiveServer2 相似,但是更加的輕量,沒有 HiveServe2 中複雜而繁重的 SQL 解析,同時又沒有 Spark Thrift Server 這種自身就是一個 YARN 作業的約束。企業可以基於自身的業務流程,開發一個輕量的伺服器,在這方面位元組有非常深的實踐經驗,同時也有自己的 Spark SQL 引擎伺服器,可關注後續的動態。同時業界也有其他企業做了類似的工作,例如網易開源的 Kyuubi。

Kyuubi 整個架構圖如上所示(圖片來自於 kyuubi 官網:https://github.com/apache/incubator-kyuubi)。

Kyuubi 基於 Spark SQL 之上,較好的彌補了 Spark Thrift Server 在多租戶、資源隔離和高可用等方面的不足,是一個真正可以滿足大多數生產環境場景的開源專案。但是 Kyuubi 在設計的時候考慮的是如何彌補 Spark Thrift Server 的不足,目的在於增強 Spark SQL 的能力,而不是對等設計一個可以替換 Hive 元件的服務。因此對於遺留專案來說遷移成本較高,Spark SQL 與 Hive 有著兩套不相容的 SQL,在使用 Kyuubi 的時候如何是遺留系統遷移成本將是一個非常大的工作量。

而行業也有開源的 Spark Thrift Server,該思路是非常優秀的,但是因為開發過程中有點太過於侷限,導致依舊存在很多問題,主要體現在:

  • Driver 單點:整個 Spark thrift server 以一個 Spark 任務的形式執行在 YARN 上,所有的請求都執行在一個 Driver 中,一旦 Driver 掛掉後,所有任務都會同時失敗。

  • 資源隔離:因為 Spark thrift server 是以 Spark 任務的形式執行在 YARN 上,因此提交的任務如果有跨佇列提交需求的時候,Spark thrift server 很難支撐,其次多個任務執行在同一個 Driver 之中,資源使用會相互影響,很難更精細化的進行資源的管理。

  • 多租戶:Spark thrift server 從請求層面是可以支援多使用者的,但是從架構層面來看 Spark thrift server 是一個執行在 Yarn 上的任務,它也有自己的 Application Id 有自己的任務提交者,因此它實際上是以一個超級管理員的身份執行,再做二次租戶隔離,必然存在一定的資源安全問題。

  • 高可用:Spark thrift server 本身是沒有高可用涉及的,因此它的高可用需要自行單獨設計,且還得考慮客戶端的相容,例如 Hive JDBC 將 HA 資訊儲存在 ZK 中,而 Spark thrift server 沒有這樣的機制,因此高可用的實施成本較高。

因此雖然 Spark 提供了 Spark thrift server 服務用來提供類似 JDBC 這樣的介面互動方式,但是目前依舊缺乏很多生成功能,導致在生產環境使用的情況非常少,Spark thrift server 更像是一個小眾的半成品,小修小補的嘗試著解決部分問題,但是沒有給予一個徹底的方案,導致現在有點缺乏實際的生產應用。

位元組跳動在 Spark SQL 的優化實踐

位元組跳動的數倉在 2020 年全面從 Hive 遷移至 Spark SQL,除了元件層面的原始碼修改外,在使用層面也對 Spark 做了非常多的優化。

資料湖引擎整合

Hudi,Iceberg 等資料湖引擎目前使用的越來越廣泛,位元組內部在使用 Spark SQL 的時候也存在需要使用資料湖引擎的需求,因此需要將資料湖引擎整合到 Spark SQL 中,這個過程碰到非常多的問題。

首先在與 Iceberg 整合的時候,對體驗和易用的問題進行了優化,使用者在使用 Spark SQL 過程中,需要手動輸入很多指令,並且需要找到對應的 spark-iceberg 依賴包,這個也是目前整合 Iceberg 最常用的方案。我們的解決方式是在預先安裝的過程中,提前把 iceberg 的相關 jar 包放到 spark jars 目錄下,這樣使用者只需要指定 catalog 即可,無需再手動輸出很多指令。

其次在 Spark 與 Hive 跨引擎分析場景下使用 Iceberg,Spark 正常建立表,Presto/Trono 可以正常讀寫,但 Hive 無法正常讀寫,這個問題官方的文件也沒有清晰的描述,解決方案是需要修改 Spark 的配置檔案或者修改 Hive 的 hive-site-spark override 配置,確保初始化出來的 Spark Session 中的配置項 iceberg.engine.hive.enable 的值為 true,Hive 才能正常的讀取 Spark 建立的表。

問題上本質上是由於 Iceberg 為了支援 Hive 引擎,在整體的設計上做了一些妥協,使用了 Storage Handler 的方式去實現 Hive 對 Iceberg 格式的表的讀寫,需要顯式的指定 Hive 的 Input/Output Format 實現,而 Presto/Trono 則可以基於 Hive 的 format_type 自動識別表的格式進行識別。

在相容性上,由於 Iceberg 0.12 版本不支援 Spark 3.2,由於升級 Spark 的影響範圍非常大,於是更新了 Iceberg,使用了社群的一個 master 的 snapshot 版本進行編譯,與 Spark 3.2 進行整合。

Spark SQL 伺服器

雖然行業針對 Spark SQL 提供一個 SQL 伺服器已經有 Spark Thrift Server 或者 Kyuubi 這樣的工具,但是在位元組自身業務的背景下,這些工具並不能完全滿足要求,因此自己也設計實現了自己 Spark SQL Server,主要聚焦解決的是如下場景:

  • 相容 Hive 語義:由於位元組早期也是基於 Hive 構建的資料倉儲,後續逐步全部替換為 Spark SQL,中間必然面臨大量的系統遷移,而由於 Hive 與 Spark SQL 語義不盡相同,重寫 SQL 實現的工作量非常大,因此在位元組的 Spark SQL Server 中實現 Hive 語義和 Spark SQL 語義的相容,在實現方案上採用的時候講 Hive SQL 解析注入到 Spark 引擎中,形成一個 SQL Parser Chain,最終會匹配到某一個解析器,實現對 SQL 的解析,從而達到對整個 SQL 語義的相容。

  • 提前初始化 Spark SQL 引擎:在業務請求到達前提前在 YARN 上提交 Spark 任務,初始化資源資訊,讓整個引擎處於等待的狀態,可以減少任務提交消耗的時間,在使用者較多的情況下可以提示整體的任務執行時間。

  • 跨 Yarn 佇列的任務提交:使用者可以指定 Yarn 佇列執行任務。


如上圖所示,SQL 伺服器是一個實現了 Thrift 介面的伺服器,提供標準的 JDBC 訪問介面,Spark SQL 引擎同樣實現了 Thrift 介面,Spark SQL 引擎在服務啟動的時候便已經被提交至 Yarn,處於等待狀態。當業務任務到達的時候,由 SQL 伺服器實現引擎的篩選,匹配一個已經存在的引擎,或者重新提交一個全新的引擎用來執行任務。

SQL 伺服器支援 OpenLDAP,Kerberos 等常用的許可權認證,同時支援多種不同的隔離級別,例如 Session 級別則每一個業務 SQL 都會初始化一個 Spark SQL 引擎用來接收任務,任務執行結束後,引擎從 Yarn 中銷燬。而 User 級別則針對使用者會初始性 0-N 個引擎,常駐於 Yarn 中,處於交替執行任務。

這樣的伺服器設計打破了 Spark Thrift Server 的單 Driver 所帶來的侷限,解耦了 SQL 服務和任務執行。也就支援更細粒度的資源管理和跨佇列的任務提交。

同時也相容了 Hive 的介面,使用者可以通過如下方式訪問伺服器:

HA 訪問連結:

./bin/beeline -u jdbc:hive2://emr-5fqkwudj144d2gc1k8hi-master-1/;serviceDiscoveryMode=zooKeeper;zooKeeperNamespace=midas/ha;auth=LDAP -n emr_dev -pEMR123456emr

非 HA 訪問連結:

./bin/beeline -u jdbc:hive2://emr-master-2:10005/default;auth=LDAP” -n test_sub -pEMR123456emr

HA 模式下的資訊被記錄在 Zookeeper 中,儲存的內容格式與 HiveServer2 的內容一致,能確保使用 Hive 的客戶端可以直接訪問 HA 模式下的伺服器。

Spark SQL 多租戶


在 Hive 任務執行過程中,HiveServer2 服務承擔了提供 SQL 伺服器進行使用者身份認證,許可權判斷,以及解析 SQL 生成最終的執行計劃,再由 MR 引擎執行具體的分散式任務。

在這個過程中 HiveServer2 承擔了非常重的職責,因此需要消耗非常大的資源,因此會很大程度的影響使用者的併發。對於分散式任務執行來說,它的資源約束來自於 Yarn 作為資源管理器所分配的資源,但是在 Hive 架構下卻受限於 HiveServer2 的影響,導致使用者併發的數量無法隨著 Yarn 資源的提升進行提升。

而在 Spark SQL 引擎中,SQL 解析是下推到引擎內部,與具體的分散式任務執行合為一體,不需要單獨的伺服器去做 SQL 解析。也正因為 Spark SQL 與 Hive 在解析模組的架構存在差異,Hive On Spark 的模式會變得非常難。

針對如上的場景,位元組跳動重新設計的 SQL 伺服器只負責任務的接收,進行使用者資源,許可權和身份的判斷,然後將任務傳送給執行在 Yarn 中的 Spark SQL 伺服器。打破了 Hive 這種併發受制於 HiveServer2 和 Yarn 兩層約束的局面,只由 Yarn 的資源決定使用者的併發程度,從而極大的降低了 Spark SQL 伺服器的資源需求,增強了其穩定性,在使用者併發上有了非常大的提升。

其次通過引擎預熱的功能減少任務執行的時間,提升整體速度,引擎預熱指的是在服務啟動的時候便向 Yarn 提交 Spark SQL 引擎,處於等待的狀態,當業務請求到達的時候,基於業務型別從已經處於就緒的引擎中選擇一個引擎來執行任務。

並不是每一個預熱提交的引擎都會被選擇執行,在 SQL 伺服器中存在如下三種引擎隔離級別:

  • Session:基於每一個 connection 都會全新提交 Spark SQL 引擎,在連結斷開後,引擎從 Yarn 上銷燬。

  • User:同一個使用者可以共享多個 Spark SQL 引擎,具體的 Spark SQL 引擎個數由該使用者提交的任務資源需求決定,引擎在連線斷開後不會銷燬,直到引擎空閒時長到達上限。

  • Open:所有使用者都可共享的 Spark SQL 引擎,通常是用來應對大賬號,或者叢集不需要做許可權管理的場景。

由此可見只有在 User,Open 的級別下引擎預熱才會產生價值,預熱省去了 Spark Submit 的時間,當使用者數量足夠多,群體為統計單位所節省的時間越多。

Spark SQL 事務支援

Hive 的事務力度是基於 HiveServer2 實現的,例如通過如下語法:

CREATE TABLE tm (a int, b int) stored as orc TBLPROPERTIES ('transactional'='true', 'transactional\_properties'='insert\_only')

可開啟事務,但是由於對事務的管理是在伺服器上,因此需要開啟 ACID 的時候受影響的是整個 HiveServer2 的所有請求,而 Spark SQL 很好的整合和支援了 Hudi,Iceberg 等資料湖格式,因此在 Spark SQL 伺服器中不需要實現類似 HiveServer2 的事務機制,只需要在最終讀取處理資料的時候,採用 Hudi,Iceberg 等特性便可達到支援事務的效果。

例如對於 Icdberg 資料格式的表已支援 update、delete 操作:

MERGE INTO prod.nyc.taxis ptUSING (SELECT * FROM staging.nyc.taxis) stON [pt.id](http://pt.id) = st.idWHEN NOT MATCHED THEN INSERT *;

因此當 Spark SQL 整合了 Iceberg 後,便具有了事務能力,再配合 SQL 伺服器,便可在很低的成本上具有和 Hive 事務能力同等的效益,同時也沒有 Hive 下的一些約束,從這樣的架構設計上來看,能夠完整的替換 Hive。另外一個方面當使用者數量變多,同時資料會發生修改,更新等操作,很容易造大量的小廣播傳輸,從而引起 Driver 的 OOM。雖然大廣播也會存在 OOM 的問題,但是大廣播可以通過閾值控制,而小廣播閾值對其不生效,一旦說數量變多,很容易引起 Driver 的 OOM。位元組通過對小廣播進行合併廣播,解決大量小廣播進行傳播,導致打爆 Driver 的情況出現。

尾聲

隨著企業的業務發展越來越複雜,需要更加靈活,更加高效的數倉架構,在這樣的業務驅動背景下,Hive 的侷限變得越來越明顯,而基於 Spark SQL 靈活構建數倉的方案將會變得越來越主流。所以企業在考慮資料倉儲構建體系的時候,可以考慮如何基於 Spark SQL 構建自身資料體系,Spark 完善和開放的生態在未來必然會有更多優秀的服務會圍繞 Spark 形成強大的優勢。

我們基於企業級數倉建設的部分經驗技術也已經通過火山引擎E-MapReduce對外開放。

歡迎關注位元組跳動資料平臺同名公眾號

相關文章