網易數帆旗下易數大數據團隊開源的 Kyuubi,和 Spark 社區的Spark Thrift Server,都是經過純 SQL 語言和 JDBC 接口的方式下降大數據使用門檻的項目。本文從企業大數據應用場景關注的問題出發,對比了 Kyuubi 與 Spark Thrift Server 的差別與優劣,並引入HiveServer2 進行全面的分析。
1. Spark Thrift Server 介紹
Spark Thrift Server 是Apache Spark社區基於HiveServer2實現的一個Thrift服務,旨在無縫兼容HiveServer2。它經過JDBC接口將Spark SQL的能力以純SQL的方式提供給終端用戶。這種「開箱即用」的模式能夠最大化地下降用戶使用Spark的障礙和成本。咱們先從傳統的 Spark 做業提交方式入手,談談 Spark Thrift Server 具有的優點。前端
1.1 傳統做業方式
在沒有 Spark Thrift Server 的狀況下,Spark 做爲大數據處理工具,可能並非對全部人都那麼「友好」。git
1.1.1 門檻高程序員
用戶經過Spark提供的 Scala/Java/Python 等接口使用 Spark時都須要必定的編程基礎。同時,用戶須要具有良好的大數據背景。舉例來講,用戶須要知道他們的程序最終提交哪一個平臺上,YARN、Kubernetes或者是別的平臺?用戶也須要知道如何去配置他們所提交做業的資源使用,須要多少的 Executor 數,每一個 Executor 該配置多少的內存和CPU?他們本身又該知道怎麼去合理的使用集羣上的資源呢?用多了,會不會對其餘關鍵任務形成影響?用少了,集羣的資源是否是閒置浪費?成千上百的配置如何去設置?動態資源調度,自適應查詢,推測執行,這些關鍵特性該如何無成本的應用到各個任務中去?github
1.1.2 不安全apache
用戶經過代碼的方式訪問元數據和數據,數據安全性沒法保證,「刪庫跑路」垂手可得。全部的客戶端配置須要直接或者間接的交到用戶手中。一方面,這些配置自己就可能包含一些敏感信息;另外一方面,後臺的服務也基本上「裸露」在用戶的面前。不少企業使用 Spark 的時候都會魔改加入一些適配本身場景的特性。例如在數據安全方面,可能你們都用過或者參考過網易開源出來 spark-authorizer 插件經過 Apache Ranger 來實現細粒度的 SQL Standard Based Authorization。但這種安全特性,經過 Spark 代碼提交做業的方式,在會寫代碼的程序員面前,只是約束力不強的「君子協定」。編程
1.1.3 兼容性後端
客戶端兼容性難以保證。一個用戶的 Spark 做業最終被調度到集羣上運行,面臨着客戶端環境和集羣環境不一致,用戶做業依賴和 Spark 或 Hadoop 依賴衝突等問題。若是團隊選擇維護一個內部魔改的 Spark 或者 Hadoop 版本,在這些版本的開發過程當中,須要時刻注意是否能保持用戶接口的兼容性。在各底層版本服務端的升級換代過程當中,也須要儘量的完成用戶客戶端的升級,這時候就可能引入許多沒必要要的兼容性測試工做,並且很容易出現測試覆蓋不全的問題。緩存
1.1.4 延時高安全
Spark Application的啓動延時。按做業的生命週期維度分類,咱們能夠簡單的將 Spark 任務簡單的分爲兩種,常駐類型和很是駐類型。常駐類型做業的特色就是 Application的啓動時間相對於總任務運行時長來說忽略不計或者和計算過程徹底解綁,如 Spark Structed Streaming任務,計算過程只有 Task 線程級別的調度,低延時快響應。而很是駐類型的做業,每次都須要啓動 Spark 程序。相對而言,這個過程是很是耗時的,特別對於一些秒級分鐘級的計算任務負擔較重。多線程
1.2 Spark ThriftServer 方式
Spark ThriftServer本質上就是一個 Spark 應用在多線程場景下的應用。它在運行時啓動一個由 Driver 和 Executor 組成的分佈式 SQL 引擎。在 SQL 解析層,該服務可充分利用 Spark SQL 優化器的能力,在計算執行層,因爲 Spark ThriftServer 是常駐類型的應用,沒有啓動開銷,當沒有開啓動態分配的狀況下,整個 SQL 的計算過程爲純的線程調度模式,性能極佳。
Spark ThriftServer 架構
在這個架構的基礎上,基於 HiveServer2 實現了 Session 相關操做,來響應客戶端的鏈接和關閉請求,也實現了 Operation 相關操做,來響應客戶端查詢請求等。這些請求都由Server前端實現的線程池模型來響應。並調用Server後端的對應方法與SparkSession相關接口的綁定。而後Server後端經過一個異步線程池,將這些 Operation 提交到分佈式 SQL 引擎上真正執行。
首先,在這種模式下用戶經過簡單的 SQL 語言和 JDBC 接口完成和 Spark ThriftServer 的交互,實現本身的業務邏輯。不須要對 Spark 自己有過多的技能基礎,或者對 Spark 所運行的平臺,或者底層數據的實現有過多的關注。Spark ThriftServer 基本的容量規劃、底層服務的打通、以及後續的優化迭代均可以在服務端完成。固然也有同窗會認爲,SQL 的表達並不能知足全部的業務,但自己這個服務就是對標 HiveServer2 來給這類用戶提供純 SQL能力的。一些複雜的邏輯也能夠嘗試使用 UDF/UDAF 之類的進一步支持,基本上大部分的大數據處理工做,Spark ThriftServer都是能夠勝任的。
2 Spark ThriftServer 的侷限
從上面 Spark ThriftServer的基本架構圖咱們也能夠看出,其本質上是一個 Spark Application。用一個 Spark Application 去響應成千上萬的客戶端請求,通常會存在比較大的限制。
2.1 Driver 單點問題
對於單線程的 Spark 應用來講,Driver 節點的單點效應,制約着它能起多少Executor提升併發能力及把數據分紅多少個 Partition 來並行的處理。隨着Executor數量的上升,Driver 須要處理更多控制面的 RPC 消息,而隨着Partition的增長,Driver 也須要處理更多數據面的 RPC 消息。在 Spark ThriftServer 這個多線程模型下,它同時還要處理大量的客戶端請求,單點的效應會更加的明顯。另外,全部執行線程所依賴的Hive metastore client是一個,在訪問HMS的時候也會有較明顯的併發問題。
2.2 資源隔離問題
超大任務侵佔過多或者全部 Spark ThriftServer 的計算資源,致使其餘任務延時或者卡死。
Spark ThriftServer 的計算資源問題
若是使用Fair Scheduler Pools能夠必定程度上解決計算側的資源分配問題。可是在 Driver 調度側,難以免的還會遇到HMS,HDFS訪問單點的問題,特別是讀寫動態分區表或者大量 Union 的場景。從本質上將,CPU/內存/IO等資源隔離就應該是YARN、Kubernetes這類資源管理器該乾的事情。計算層作邏輯上的資源隔離,效果不可能理想,好比,這個問題在 Apache Impala 項目裏也一樣存在。
2.3 多租戶侷限
Spark ThriftServer 自己應該是一個支持多租戶的系統,即它能夠接受不用用戶不一樣客戶端的請求並在服務端貢獻線程池中分配這些資源完成用戶的請求返回結果。但從 Spark 自身設計角度出發,單 Spark 應用實現的 Spark ThriftServer 並不能完整支持多租戶,由於整個 Application 只有全局惟一的用戶名, 同時包括 Driver 端和 Executor 端。這個結合 HiveServer2 來說更方便理解,Server端運行的時候通常使用的 Service Principal進行啓動,客戶端鏈接帶有完整的用戶信息,接受服務端認證經過後會由服務端「假裝執行」,因此每次執行任務的實際用戶爲客戶端用戶,這裏包括了申請資源運行 MR 程序,訪問 HMS 和 HDFS 等服務。回到 Spark ThriftServer 這邊,這些資源申請和服務的訪問都交給服務端用戶去作。所以該服務端用戶必然須要全部元數據和數據的超級權限。從數據安全的角度,這樣作一方面形成潛在的權限泄露問題,另外一方面 HMS 和 HDFS 也很難去根據不一樣的用戶完成審計,所以線上出了問題通常很難追根溯源。從資源隔離和共享角度,Spark ThriftServer 佔用的是單個資源隊列(YARN Queue / Kubernetes Namespace, 這也致使很難細粒度或者彈性地控制每一個用戶可以使用的資源池大小,若是有資源計費等需求就很難知足。
2.4 高可用侷限
Spark ThriftServer 社區版本是不支持高可用(High Availability, HA)的。很難想象一個沒有高可用的服務端應用可否支撐起 SLA 的目標,相信運維人員是確定睡不安穩了。固然,要給 Spark ThriftServer 增長一個 HA 並不難,例如社區老早就有人提出這個問題,並附上了PR,詳見SPARK-11100。對於 Spark ThriftServer 的 HA 實現,各個廠商魔改的方式大致上分兩種思路,即「主從切換」和「負載均衡」。主從切換由Active Spark ThriftServer 和若干 Standby Spark ThriftServer 構成,當 Active Spark ThriftServer掛掉以後,Standby 節點觸發選主成爲 Active 節點接替。這裏存在不少問題,第一,主從模式下只有一個 Active 節點,也就面臨着嚴重的 Spark Driver 單點問題,並不能提供很高的併發能力;第二,因軟硬件故障,而發生主從切換時,意味着「所有」的當前任務失敗,各個 Spark 做業的Failover 並不輕量,這基本上已經可定義爲P0級別的「事故」,SLA 確定是要受到影響了;第三,Standby 節點形成嚴重的集羣資源浪費,不管是是否開啓 Spark 動態資源分配的特性,從主從切換的更加順滑的目的出發,都要爲Standby節點「搶佔」必定的資源;第四,通常而言,軟件故障的機率遠遠大於硬件故障,而 Spark ThriftServer 軟件故障通常是因爲客戶端高併發請求或者查詢結果集過大致使的,這種模式下,一旦發生切換,客戶端重試機制同時觸發,新的 Standby 節點只會面對更大的宕機風險。爲了解決 Spark ThriftServer Driver 單點問題,更加合適的作法是負載均衡模式,這樣當客戶端的請求量上來,咱們只要水平的擴充 Spark ThriftServer 便可。但這種模式也有必定的限制,每一個 Spark ThriftServer 都是有狀態的,兩個服務之間並不能共享,好比一些全局臨時視圖、UDF 等,這表示客戶端每次鏈接若是要複用都必須從新建立它們。
2.5 UDF 使用的問題
包括前面談到的 UDF 在高可用下的複用問題,對單個 Spark ThriftServer 來講,還面臨這 Jar 包衝突及沒法更新和刪除的問題。另外,因爲 UDF 是直接加載到 Spark ThriftServer 服務端的,但 UDF 中包含一些無心或者惡意的邏輯,如直接調用 System.exit(-1), 或者相似 Kerberos 認證等影響服務全局的一些操做,可能直接將服務殺掉。
3 Kyuubi V.S. Spark Thrift Server
HiveServer2 (Hive on Spark) |
Spark ThriftServer | Kyuubi | |
---|---|---|---|
接口 | HiveJDBC | HiveJDBC | HiveJDBC |
SQL 語法 | Hive QL | Spark SQL | Spark SQL |
SQL 優化器 | Hive Optimizer | Spark SQL Catalyst | Spark SQL Catalyst |
SQL 解析 | Server 端 | Server 端 | Engine 端 |
UDF 加載 | Server 端 | Server 端 | Engine 端 |
任務提交 | 一條 SQL 被拆分紅多個 RemoteDriver實現的 Spark 程序進程進行提交 | 全部 SQL 共享 Server 這個 Spark 程序,純分佈式線程調度 | Kyuubi 經過 Engine 緩存隔離策略,經常使用的隔離模式以下, 1. USER 級別隔離,同用戶的不一樣 JDBC 鏈接共享屬於用戶的 Engine;2. CONNECTION 級別隔離,一個 JDBC 鏈接一個 Engine,一個鏈接內的全部 SQL 由同一 Engine 負責執行 |
Spark 兼容性 | 特定單一版本支持 | 內置,和 Spark版本綁定 | 多版本適配 |
Catalog 管理 | HMS | HMS | HMS、各類數據湖框架及第三方Catalog |
高可用 | 有 | 無 | 有 |
多租戶 | 有 | 無 | 有 |
權限控制 | SQL Standard,細粒度 | 無 | SQL Standard,細粒度 |
性能 | 通常 | 好 | 好 |
客戶端併發 | 水平擴展 | 無擴展能力,可打Patch | 水平擴展 |
動態隊列 | SQL 粒度支持 | 無 | Engine 粒度 |
動態資源配置 | SQL 粒度 | 無 | Engine 粒度 |
計算資源管理 | YARN | 自我管理,Fair Scheduler Pools | YARN、 Kubernetes 等 |
資源佔用週期 | SQL 執行期間 | 永久,可支持動態資源分配 | 資源經過 Engine 維度來申請和釋放 1. CONNECTION 級別隔離模式,JDBC 鏈接開啓至斷開2. 其餘隔離模式,全部鏈接斷開 + 緩存TIMEOUT,可支持 Engine 常駐 3. 全部隔離模式均支持動態資源分配 |
3.1 接口一致性
從接口和協議上來講,Kyuubi、Spark Thrift Server以及HiveServer2是徹底一致的。所以,從用戶的角度來說,整體使用方式是不變的。與HiveServer2相比,前二者帶給用戶最大的不一樣應該就是性能上的飛躍。用戶能夠選擇市面上既有的 BI 工具, 如網易易數、 DBeaver,及Hadoop生態圈的Hue / Hive Beeline 等工具完整適配三個不一樣的服務。
從 SQL 語法兼容的角度,Kyuubi 和 Spark Thrift Server 同樣徹底委託 Spark SQL Catalyst 層完成,因此和 Spark SQL 全兼容。而 Spark SQL 也基本上徹底支持 Hive QL集合,只有少許可枚舉的 SQL 行爲及語法上的差別。
3.2 多租戶架構
維基百科: 多租戶技術(英語:multi-tenancy technology)或稱多重租賃技術,是一種軟件架構技術,它是在探討與實現如何於多用戶的環境下共享相同的系統或程序組件,而且仍可確保各用戶間資料的隔離性。
Kyuubi、Spark ThriftServer 和 HiveServer2 的使用場景是一個典型的多租戶架構。
在資源層面,咱們要考慮的是在資源隔離的基礎上 1) 如何在邏輯上更加安全和高效的利用這些計算資源 2) 如何賦予用戶對屬於本身的資源「足夠」的控制能力。
HiveServer2 在這方面應該是作的最暴力最靈活的一個,每條 SQL 都被編排成若干 Spark 獨立程序進行執行,在執行前均可以設置隊列、內存等參數。但這種作法一個方面是致使了極高 Spark 啓動時延,另外一個方面也沒法高效地利用計算資源。
Spark ThriftServer 的方向則徹底相反,由於 Spark 程序只有一個且已經預啓動,從用戶的接口這邊已沒法進行隊列信息、內存參數等資源調整。內部能夠經過Fair Scheduler Pools進行「隔離」和「共享」,只能對不一樣的 Pool 設置權重,而後將 SQL 任務拋進不一樣的 Pool 而獲得公平調度的能力,離真正的意義上的資源隔離還差的很遠。
Kyuubi 在這個方面在其餘兩個系統的實現上,作了「中和」。圍繞 Kyuubi Engine 這個概念實現多租戶特性,一個 Engine 即爲一個 Spark 程序。
-
從資源隔離的角度,不一樣租戶的 Engine 是隔離的,一名用戶只能建立和使用他本身的一個或者多個 Engine 實例,資源也只能來自有權限的隊列或者Namespace。
-
從用戶對資源的控制能力上來說,用戶能夠在建立 Engine 實例的時候對其資源進行初始化配置,這種作法雖然沒有 HiveServer2 那樣靈活,但能夠免去大量的 Spark 程序啓動開銷。
-
從資源共享的角度,Engine 支持用戶端配置不一樣的共享級別,若是設置爲 CONNECTION 級別共享,用戶的一次 JDBC 鏈接就會初始化一個 Engine,在這個鏈接內,用戶能夠執行多個 Statement 直至鏈接關閉。若是設置爲 USER 級別共享,用戶的屢次 JDBC 都會複用這個 Engine,在高可用模式中,不管用戶的鏈接打到哪一個 Kyuubi Server 實例上,這個 Engine 都能實現共享。同一個用戶能夠爲本身的每一個鏈接設置不一樣的隔離級別。好比一些 ETL 流水做業或者定時報表任務,能夠選擇 CONNECTION 級別共享級別已得到任務粒度的精細資源控制。而在一些交互式分析的場景中,則能夠選擇 USER 級別共享並設置合適的緩存時間以得到出色的交互響應能力。
在數據層面,咱們須要考慮就是元數據和數據訪問的安全性,不一樣的用戶只能訪問其有權限訪問的數據。如文件級別的ACL權限或者是元數據層面的基於 SQL 標準實現的諸如 SELECT/CREATE/ATTER/UPDATE/DROP 等類型和 DATABASE/TABLE/COLUMN 等級別的細粒度權限控制。這一切的實現都依賴一個基本的概念多租戶,Spark ThriftServer 單用戶顯然是不可能適配這套模型的,而 Kyuubi 因爲實現了多租戶,自然就支持了文件級別的 ACL 權限控制,另外 經過適配 spark-authorizer 插件,也有能力實現 SQL 標準的權限控制。
3.3 高可用能力
Spark ThriftServer 的高可用問題前文已經涉及,這裏再也不贅述。在 Kyuubi 中,咱們以負載均衡模式提供高可用, Kyuubi 服務自己不是集羣資源的消耗大戶,水平擴展不會有過多的負擔。
3.4 客戶端併發
不管是 HiveServer2 仍是 Spark ThriftServer 的 SQL 的編譯優化都在 Server端完成,這個階段須要單點地完成元數據的獲取,對於大型分區表掃描存在必定的瓶頸。另外 Spark ThriftServer 同時兼具這 Spark 計算側的 Driver 角色,負責調度服務,原則上 Executor 數量越多,處理的數據量越大,Server 端的壓力也就越大。在 Kyuubi 中,用戶提交的 SQL 編譯優化都在 Engine 端完成,SQL Analyzer 階段對於元數據的訪問獲取能夠從 Server 端釋放出來,同時全部的計算過程也都在 Engine 端完成,極大下降了 Kyuubi Server 端的工做負載。
3.5 服務穩定性
撇開高可用功能不講,單個 Spark ThriftServer 因爲客戶端響應邏輯和 Spark 計算強耦合,一方面提升客戶端併發能力則會分走大量的 Driver 端線程資源,另外一方面 Driver 端在高計算負載下面臨繁重的 GC 問題,喪失必定的客戶端響應能力。當部分查詢返回較大的結果集時,也很容易形成 OOM 的風險。 Kyuubi 因爲 Server 和 Engine 分離的設計,在這方面徹底不存在問題。對於 UDF 使用的問題,由於是在 Engine 內部進行加載和使用的,若是用戶「行車不規範」,最多也就「本身兩行淚」,不會對服務的穩定性形成任何影響。
4 總結
Kyuubi 在統一接口基礎上,拓展了 Spark ThriftServer 在多租戶模式下的使用場景,並依託多租戶概念得到了完善的資源隔離共享能力和數據安全隔離的能力。而得益於 Kyuubi Server 和 Engine 鬆耦合的架構極大提高了服務自身的併發能力和服務穩定性。另外,因爲篇幅有限,Kyuubi 對數據湖的友好支持將在之後的分享中進行介紹。
做者簡介:燕青,目前就任於網易數帆-易數事業部,專一於開源大數據領域。網易數帆開源 Kyuubi 數據湖探索平臺做者,Apache Spark Committer,Apache Submarine Committer。
相關文章: