極光筆記丨Spark SQL 在極光的建設實踐

極光高級工程師——蔡祖光

前言

Spark在2018開始在極光大數據平臺部署使用,歷經多個版本的迭代,逐步成爲離線計算的核心引擎。當前在極光大數據平臺每天運行的Spark任務有20000+,執行的Spark SQL平均每天42000條,本文主要介紹極光數據平臺在使用Spark SQL的過程中總結的部分實踐經驗,包括以下方面內容:

Spark Extension的應用實踐
Spark Bucket Table的改造優化
從Hive遷移到Spark SQL的實踐方案

一、Spark Extension應用實踐

Spark Extension作爲Spark Catalyst擴展點在SPARK-18127中被引入,Spark用戶可以在SQL處理的各個階段擴展自定義實現,非常強大高效

1.1 血緣關係解析

在極光我們有自建的元數據管理平臺,相關元數據由各數據組件進行信息收集,其中對Spark SQL的血緣關係解析和收集就是通過自定義的Spark Extension實現的。

Spark Catalyst的SQL處理分成parser,analyzer,optimizer以及planner等多個步驟,其中analyzer,optimizer等步驟內部也分爲多個階段,爲了獲取最有效的血緣關係信息,我們選擇最終的planner階段作爲切入點,爲此我們專門實現了一個planner strategy進行Spark SQL物理執行計劃的解析,並提取出讀寫表等元數據信息並存儲到元數據管理平臺

1.2 權限校驗

在數據安全方面,極光選擇用Ranger作爲權限管理等組件,但在實際使用的過程中我們發現目前社區版本的Ranger主要提供的還是HDFS、HBase、Hive、Yarn的相關接入插件,在Spark方面需要自己去實現相關功能,對於以上問題我們同樣選擇用Spark Extension去幫助我們進行權限方面的二次開發,在實現的過程中我們藉助了Ranger Hive-Plugin的實現原理,對Spark SQL訪問Hive進行了權限校驗功能的實現。

1.3 參數控制

隨着數據平臺使用Spark SQL的業務同學越來越多,我們發現每個業務同學對於Spark的熟悉程度都有所不同,對Spark配置參數的理解也有好有壞,爲了保障集羣整體運行的穩定性,我們對業務同學提交的Spark任務的進行了攔截處理,提取任務設置的配置參數,對其中配置不合理的參數進行屏蔽,並給出風險提示,有效的引導業務同學進行合理的線上操作。

二、Spark Bucket Table的改造優化

在Spark的實踐過程中,我們也積極關注業內其它公司優秀方案,在2020年我們參考字節跳動對於Spark Bucket Table的優化思路,在此基礎上我們對極光使用的Spark進行了二次改造,完成如下優化項:

Spark Bucket Table和Hive Bucket Table的互相兼容
Spark支持Bucket Num是整數倍的Bucket Join
Spark支持Join字段和Bucket字段是包含關係的Bucket Join

上述三點的優化,豐富了Bucket Join的使用場景,可以讓更多Join、Aggregate操作避免產生Shuffle,有效的提高了Spark SQL的運行效率.在完成相關優化以後,如何更好的進行業務改造推廣,成爲了我們關心的問題。

通過對數據平臺過往SQL執行記錄的分析,我們發現用戶ID和設備ID的關聯查詢是十分高頻的一項操作,在此基礎上,我們通過之前SQL血緣關係解析收集到的元數據信息,對每張表進行Join、Aggregate操作的高頻字段進行了分析整理,統計出最爲合適的Bucket Cloumn,並在這些元數據的支撐下輔助我們進行Bucket Table的推廣改造。

三、Hive遷移Spark

隨着公司業務的高速發展,在數據平臺上提交的SQL任務持續不斷增長,對任務的執行時間和計算資源的消耗都提出了新的挑戰,出於上述原因,我們提出了Hive任務遷移到Spark SQL的工作目標,由此我們總結出瞭如下問題需求:

如何更好的定位哪些Hive任務可以遷移,哪些不可以
如何讓業務部門無感知的從Hive遷移到Spark SQL
如何進行對比分析,確認任務遷移前後的運行效果

3.1 Hive遷移分析程序的實現

在遷移業務job時,我們需要知道這個部門有哪些人,由於Azkaban在執行具體job時會有執行人信息,所以我們可以根據執行人來推測有哪些job。分析程序使用了元數據系統的某些表數據和azkaban相關的一些庫表信息,用來幫助我們收集遷移的部門下有多少hive job,以及該hive job有多少sql,sql語法通過率是多少,當然在遷移時還需要查看Azkaban的具體執行耗時等信息,用於幫助我們在精細化調參的時候大致判斷消耗的資源是多少。

由於線上直接檢測某條sql是否合乎spark語義需要具有相關的讀寫權限,直接開放權限給分析程序不安全。所以實現的思路是通過使用元數據系統存儲的庫表結構信息,以及azkaban上有采集業務job執行的sql信息。只要擁有某條sql所需要的全部庫表信息,我們就能在本地通過重建庫表結構分析該條sql是否合乎spark語義(當然線上環境和本地是有不同的,比如函數問題,但大多情況下是沒有問題的)。

                                                        圖3-1-1

以下爲某數據部通過分析程序得到的SQL通過率

3.2 SQL執行引擎的無感知切換

目前業務方使用Hive的主要方式是通過beeline去連接hiveserver2,由於livy也提供了thriftserver模塊,所以beeline也可以直接連接livy。遷移的策略就是先把合乎Spark語法的SQL發往livy執行,如果執行失敗再切換到Hive進行兜底執行。

beeline可獲取用戶SQL,啓動beeline時通過thrift接口創建livy session,獲取用戶sql發送給livy 執行,期間執行進度等信息可以查詢livy獲得,同時一個job對應一個session,以及每啓動一次 beeline對應一個session,當job執行完畢或者beeline被關閉時,關閉livy session。(如果spark不能成功執行則走之前hive的邏輯)

                                                        圖3-2-1

有了以上切換思路以後,我們開始着手beeline程序的修改設計

beeline重要類圖如圖3-2-2所示, Beeline類是啓動類,獲取用戶命令行輸入並調用Commands類去 執行,Commands負責調用JDBC接口去執行和獲取結果, 單向調用流程如圖3-2-3所示。

                                                    圖3-2-2

                                                       圖3-2-3

由圖3-2-2和圖3-2-3可知,所有的操作都是通過DatabaseConnection這個對象去完成的,持有這個 對象的是DatabaseConnections這個對象,所以多計算引擎切換,通過策略適配

DatabaseConnections對象,這樣就能在不修改其他代碼的情況下切換執行引擎(即獲取不同的 connection)

                                                       圖3-2-4

3.3 任務遷移黑名單

前文有說到,當一個Hive任務用SQL分析程序走通,並且在遷移程序用livy進行Spark任務提交以後,還是會有可能執行失敗,這個時候我們會用Hive進行兜底執行保障任務穩定性。但是失敗的SQL會有多種原因,有的SQL確實用Hive執行穩定性更好,如果每次都先用Spark SQL執行失敗以後再用Hive執行會影響任務效率,基於以上目的,我們對遷移程序開發了黑名單功能,用來保障每個SQL可以找到它真正適合的執行引擎,考慮到beeline是輕量級客戶端,識別的功能應該放在livy-server側來做,開發一個類似HBO的功能來將這樣的異常SQL加入黑名單,節省遷移任務執行時間。

目標: 基於HBE(History-Based Executing)的異常SQL識別

有了上述目標以後我們主要通過如下方式進行了SQL黑名單的識別切換

SQL識別限定在相同appName中(縮小識別範圍避免識別錯誤)
得到SQL抽象語法樹的後續遍歷內容後生成md5值作爲該sql的唯一性標識
把執行失敗超過N次的SQL信息寫入黑名單
下次執行時根據賦值規則比較兩條SQL的結構樹特徵
對於在黑名單中的SQL不進行Spark SQL切換

3.4 遷移成果

今年經過遷移程序的遷移改造,HSQL最大降幅爲50%+(後隨今年業務增長有所回升)

四、Spark3.0的應用

當前極光使用的Spark默認版本已經從2.X版本升級到了3.X版本,Spark3.X的AQE特性也輔助我們更好的使用Spark

實踐配置優化:

spark3.0.0參數

動態合併shuffle partitions

spark.sql.adaptive.coalescePartitions.enabled true

spark.sql.adaptive.coalescePartitions.minPartitionNum 1

spark.sql.adaptive.coalescePartitions.initialPartitionNum 500

spark.sql.adaptive.advisoryPartitionSizeInBytes 128MB

動態優化數據傾斜,通過實際的數據特性考慮,skewedPartitionFactor我們設置成了1

spark.sql.adaptive.skewJoin.enabled true

spark.sql.adaptive.skewJoin.skewedPartitionFactor 1

spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes 512MB

五、後續規劃

目前針對線上運行的Spark任務,我們正在開發一套Spark全鏈路監控平臺,作爲我們大數據運維平臺的一部分,該平臺會承擔對線上Spark任務運行狀態的採集監控工作,我們希望可以通過該平臺及時定位發現資源使用浪費、寫入大量小文件、存在slow task等問題的Spark任務,並以此進行有針對性的優化,讓數據平臺可以更高效的運行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章