一條SQL在 MaxCompute 分散式系統中的旅程

芊寶寶最可愛發表於2019-11-06

摘要:2019杭州雲棲大會大資料技術專場,由阿里雲資深技術專家侯震宇、阿里雲高階技術專家陳穎達以及阿里雲資深技術專家戴謝寧共同以“SQL在  MaxCompute 分散式系統中的旅程 ”為題進行了演講。本文首先介紹了 MaxCompute 計算平臺及其特點、超大規模企業級SQL引擎和其功能。然後講解了如何構建企業級分散式智慧排程執行框架。最後介紹了新一代列式儲存引擎AliOrc及最佳化方式。

以下為精彩影片內容整理:


MaxCompute–面向企業的超大規模計算

  • 全託管,多租戶,超大規模平臺

    MaxCompute擁有龐大的使用者群體,支援阿里集團的各個關鍵業務和複雜場景,支援多個網際網路新興企業核心業務,以及支援關係國計民生、國家安全的關鍵行業。同時擁有超大規模計算儲存,包括單日千萬以上計算任務、多EB級別儲存量、10萬臺以上伺服器以及全球超過十個資料中心。
  • 企業級高效能運算引擎

    TPC-BigBench是更面向於大資料運算的BigBench,覆蓋一些複雜型別,包括機器學習場景,更貼近於大資料場景的業務。在2017年,阿里的TPC-BigBench首個透過100TB 驗證的引擎。在2018年,TPC-BigBench 首個達到18000+引擎。在2019年,進一步提升到 25000+,正式公佈到TPC官網。

MaxCompute不僅僅在阿里集團內部被廣泛的使用,也支撐著許多著名的網際網路方面的廠商,以及關係到國計民生、國家安全方面的應用。

一條SQL在 MaxCompute 分散式系統中的旅程


超大規模企業級SQL引擎– MaxCompute UniSQL

一條SQL在分散式系統中的旅程

一條SQL在 MaxCompute 分散式系統中的旅程



上圖所示為執行SQL任務中的大概流程。首先使用一條SQL語句,透過Compile,可以生成一個邏輯的執行計劃,這個邏輯的執行計劃是計算機能夠理解的,再經過Optimize過程,無論邏輯計劃有多複雜,都要翻譯成針對目前叢集和執行時刻的Runtime最優的物理執行計劃,對於每一個Optimize不一定與原始的SQL相關。然後經過計算排程框架,使得合理快速的安排執行任務。由排程框架做的安排應用到每臺機器之後,每臺機器都會有一個SQL的執行時(Runtime Engine),它是真正能夠理解物理執行計劃的,並且一步一步把資料從Storage中讀出來,再經過Shuffle得到結果,最後返回到Storage中。可以看出,執行時本身的效能是非常關鍵的,僅僅一條SQL語句有可能消耗幾百T的data,這時,Storage的效能也是至關重要的。

SQL的功能

  • Not Only SQL – 指令碼模式

一條SQL在 MaxCompute 分散式系統中的旅程


上圖為SQL的一個指令碼,上面是配置語句,下面是建立的表,每句都是SQL的語句,但是這些SQL語句都可以串在一個指令碼里,當表述一個非常複雜的邏輯時,不需要把指令碼寫成巢狀的形式,這種方式更靈活,能夠支撐更復雜的業務場景。阿里內部有非常複雜的業務場景,過去不支援這種方式時,使用者是使用巢狀的方式,使指令碼變得複雜和扭曲,並且有大量的重複,以致不能解決時,就會將其拆分,再透過外部調動的方式串連起來。因為人如果承受不了維護的代價,就要引用額外效能的開銷,後面的語句就要引用前面的語句。不管指令碼有多複雜,經過編譯器之後,還是一個單一完整的執行計劃,並不會帶來額外的開銷。最佳化器看到的上下文越多,最佳化的機會越多,形成單一完整的執行計劃之後,就可以以最高效的方式執行整個業務模式。此外,DataWorks也是支援這種模式的。透過指令碼模式可以效仿C++或者Java來寫SQL。

  • Not Only SQL– 引數化檢視

一條SQL在 MaxCompute 分散式系統中的旅程


例如,在寫C++或者Java時,經常在公共的邏輯中抽取出來一個函式,把公共的邏輯放到某一個模組裡,這個過程視為程式碼的重用機制。但是,標準的SQL,尤其是大資料的SQL是缺乏這種機制的。對於阿里這麼複雜的場景,這種需求是很迫切的。底層的資料集提供了各個部門都需要的基礎的資料,不同的業務部門可能都要消耗這部分資料,消耗的方式是不同的。這時,也想像C++或者Java那樣抽取一個函式,在MaxCompute中是可以實現的。在MaxCompute裡,上圖中的紅框除了作為普通的view,也可以封裝一些SQL複雜的邏輯和對資料的讀取,可以把表的變數傳入,這時就可以實現像C++或者Java中函式的功能,可以把SQL裡公共的業務邏輯封裝在一起,同時結合上文的指令碼模式,引數化檢視就可以組織非常複雜的SQL的業務邏輯用來支撐非常複雜的業務場景。

  • Not Only SQL – IF/ELSE

一條SQL在 MaxCompute 分散式系統中的旅程


一般的大資料不支援IF/ELSE,但對於IF/ELSE是有需求的。例如,每週做一次全量的計算,但每天只做增量的計算,如果沒有IF/ELSE的支援,就需要把指令碼拆成兩個,透過排程的框架串連起來。但是,在MaxCompute中結合指令碼模式,可以直接的寫入IF語句或SELECT語句,如果返回的是異常的結果,直接可以放在一個表示式裡,決定執行SQL的分支。所有的SQL的功能都是針對複雜的應用場景的需要。

  • Not Only SQL – UDT & TRANSFROM

一條SQL在 MaxCompute 分散式系統中的旅程


普通的SQL都會有基本的資料型別,有時也有複雜型別,但都是屬於給定範圍的資料型別。當資料型別特別複雜時,在MaxCompute裡可以直接使用。右側框架是將Java和SQL無縫的融合在一起,無需UDF封裝。左側為SELECT TRANSFORM,是直接就可以在SQL裡呼叫shell指令碼,並且完全相容Hive。

SQL的效能

  • SQL Engine for Huge Data - Adaptive Join

一條SQL在 MaxCompute 分散式系統中的旅程


Adaptive Join包括Hash Join和Merge Join。Hash Join的效能是比較好的,但有時碰到不合適的場景時,特別是有非常多的Hash衝突時,效能就會變得很差。Merge Join的特點是能夠提供一個效能的下限。可以透過動態的選擇適合哪種場景,以便做智慧的選取。

  • SQL Engine for Huge Data – Advanced Shuffle

一條SQL在 MaxCompute 分散式系統中的旅程


Shuffle也有針對特定大規模系統的最佳化,包括提升Shuffle 70%的效能,提升大規模共享叢集效能,提升穩定性,降低IO壓力。具體包括以下最佳化方式:

1、Greysort模式(Mapper不排序,Reducer排序),增加與下游流水線機會;下游轉化為HashJoin時消除排序 
2、Encoding & Adaptive列式壓縮,降低IO與Cache Miss 
3、最佳化記憶體結構,降低Working Set Size並消除Pointer Chasing

企業級分散式智慧排程執行框架

打造企業級分散式排程執行系統

一條SQL在 MaxCompute 分散式系統中的旅程



整個系統的發展有兩個維度,一個維度是系統的規模,隨著系統規模的不斷成長,對於分散式排程執行系統要面對每天千萬級需要解決的問題,在阿里這個大體量的資料下,單個分散式作業規模已經能達到數十萬個計算節點,已經有上百億連線和執行數萬臺的物理機。

另一個維度是系統的成熟度,一個系統成為企業級的分散式執行排程系統就需要達到成熟度,包括三個階段,第一個階段是可用性(正確性),一個作業在單機系統上執行的結果和分散式系統上執行的結果是不一樣的,尤其是在系統的超大規模上,在面對系統各種各樣的節點失敗問題、網路層的失敗問題和各種容災問題時,怎樣透過正確的方式能保證作業正確的產出是很重要的。第二階段是夠用,是指每一個計算的系統都要鍛造自己的效能,能在各種各樣的benchmark上標準結果,透過此方法來提升效能。第三個階段是好用(智慧化),是指在動態執行過程中擁有動態能力和自適應能力,可以根據作業的不同特點來調整作業執行的計劃。

企業級分散式計算排程框架

企業級分散式計算排程框架分為三個階段:

  • 動態的智慧執行

一條SQL在 MaxCompute 分散式系統中的旅程


上圖所示為阿里的一個作業在離開最佳化器以後,在分散式系統裡執行的過程。可以理解為從邏輯圖到物理圖對映的過程。

一條SQL在 MaxCompute 分散式系統中的旅程



上圖所示為三個階段的作業,第一個階段是作業提交開始執行,第二個階段是根據實際產出動態調整併發,第三個階段是產生所需資料提前結束作業。

一條SQL在 MaxCompute 分散式系統中的旅程



上圖所示為智慧化DAG執行的動態邏輯圖,包括Sorted Merge Join和Broadcast Join兩種演算法。其中Sorted Merge Join的特點包括經典分散式join演算法,可支援大規模作業,可用範圍廣(slow but reliable),代價較昂貴 (full shuffle + sort),且shuffle可能帶來資料傾斜。Broadcast Join的特點是隻適用特定型別作業 (一路輸入可載入單計算節點記憶體),非適用場景上可能導致OOM,作業失敗。

一條SQL在 MaxCompute 分散式系統中的旅程



對動態的選擇執行計劃,在理想情況下都希望資料的分佈是均勻的,並且可以理解資料的特性,所以最佳化器都可以做出“最佳”的計劃,尤其是在做benchmark時,但是由於源資料統計不準確 、中間資料特性波動 ,所產生資料的特點是沒有辦法提前預估的,所以允許最佳化器來給一個非確定的執行計劃(Conditional Join),這時,最佳化器會給出兩個執行路徑的計劃,排程執行框架可以根據上游實際產生的資料量,動態的調整邏輯圖的執行。

一條SQL在 MaxCompute 分散式系統中的旅程



上圖所示為併發度的例子。簡單的併發調整是根據上游總資料量直接取平均作為併發,僅支援向下調整,但問題是資料可能是傾斜的,這種方法已不再適用。下面給出兩種新的排程方法:

1、依據分割槽資料統計調整:避免併發調整加重資料傾斜,可向上向下調整。
2、分割槽統計基礎上,自動切分大分割槽:雙重調整,消除分割槽內的資料傾斜,並支援資料處理歸併,以保留分割槽特性。

  • 高效作業管理

一條SQL在 MaxCompute 分散式系統中的旅程


對於阿里如此大規模的作業,排程的敏捷度是十分重要的,因為叢集規模很大,一個作業怎樣理解各個計算節點和物理機的狀態,做智慧的容錯和預判性的容錯是阿里所做的一項工作。隨著作業規模越來越大,一個非常優秀的排程框架能帶來的效能提升會越來越明顯。

  • 多種計算模型融合

一條SQL在 MaxCompute 分散式系統中的旅程


阿里整個計算平臺作為飛天的底座,不僅僅執行SQL,也有可能執行其他。最經典的SQL是batch執行。離線和一體式的執行是資源利用率和效能最佳化的兩個極端,作為一個使用者,會同時關注執行效能和資源利用率,需要思考的問題是,怎樣在兩個點中達到平衡。因此,阿里也支援一種稱為bubble的排程,所謂bubble排程是允許一個作業的子圖同時排程,下游的子圖分佈排程,在不同的SQL上會有不同的效果。例如。在TPCH11的情況下,相對於離線(batch)會有66%的效能提升,相對於一體式(all-in-one)會節省3倍的資源,同時獲取95%的效能。

新一代列式儲存引擎AliOrc

在AliOrc的里程中,起點和終點都是在儲存層,資料的讀和寫是AliOrc執行的開始和結束,儲存引擎作為AliOrc的底座,承擔著一個非常重要的作用。

基於Apache Orc的深度最佳化

一條SQL在 MaxCompute 分散式系統中的旅程



整個計算引擎是基於列結構的,技術的出發點是Apache Orc。在此基礎上,阿里做了很多深度的最佳化,包括I/O維度、記憶體最佳化、索引和資料編碼壓縮。其中有一部分已經貢獻到了社群。

新一代列式儲存引擎

新一代列式儲存引擎包括以下技術方面:

  • 並行化編碼技術

一條SQL在 MaxCompute 分散式系統中的旅程


對於有一系列的大數和小數,直接存放時會產生4個位元組,而對於小數,前面會產生很多的零,這些零是沒有意義的。並行化編碼技術的主要思想就是將冗餘的資訊刪掉,將真正有意義的batch留下,並且pack到一起。這種編碼方式的好處是能實現並行化。此外,還進行了一些擴充套件,包括對有序資料的最佳化,以及對資料的編碼最佳化。同時重新設計了編碼儲存格式,更利於記憶體對齊,以及列儲存。

一條SQL在 MaxCompute 分散式系統中的旅程



從測試的結果來看,此編碼技術比傳統遊程編碼速度快4到6倍,壓縮率提升大概10%左右,在反應到TPC Benchmark表掃描效率提升24%。之所以有如此快的結果,是因為使用AVX256一條指令可以處理8個64位數,或者16個32位數,同時充分利用函式模板展開,最大程度避免迴圈和分支預測失敗。

  • 非同步並行IO

一條SQL在 MaxCompute 分散式系統中的旅程


阿里是屬於列儲存引擎的,是指在同一個列是放在一起的,好處是在讀資料時選擇幾個列放到儲存引擎中去讀,就不需要讀所有的列。假設在上圖中的場景中,有三個列為A、B、C。最早的IO模型是序列的,存在許多等待時間。因此,阿里做了一個改進為Prefetch模型,IO是不需要一個一個發出去的,在一開始時可以將三個讀取引擎一起發出去,但是需要一個一個的等待它們回來,雖然有了一些提升,但是還仍然存在IO等待的時間。目前為止,改進的模型為Prefetch+Async Paraller IO,是將IO全部並行化,將三個一起發出去之後,並不需要按照原來A、B、C的順序等待,可以按照回來的順序做解壓和解碼。這樣做可以對IO等待的時間降到最小。

一條SQL在 MaxCompute 分散式系統中的旅程



如上圖所示,非同步並行IO與同步讀取相比較,IO等待時間減少97%,端到端時間減少45%。

  • 延遲讀取、延遲解碼

    為了進一步的提高效能,減少資料讀取量,從而減少資料解碼、解壓縮成為了關鍵。 


一條SQL在 MaxCompute 分散式系統中的旅程



如上圖所示為延遲讀取的一個例子,透過只讀取DEPT列,把ADDRESS以及SALARY列延遲到過濾之後讀取,可以大幅減少了不必要的資料讀取。 

一條SQL在 MaxCompute 分散式系統中的旅程



對於字串型別的列,有一種方法叫字典編碼,是指將字串裡不一樣的Key找出並且給予ID,這時,資料在存放時是不需要存放整個字串的,只需要存放ID就可以。但是使用此方法是很耗時的。由此,做了以下改進:

一條SQL在 MaxCompute 分散式系統中的旅程



使用延遲解碼,跳過解碼步驟,直接在字典上匹配,再以ID到資料列搜尋。好處是減少了字串匹配次數以及減少了字典解碼時間。

一條SQL在 MaxCompute 分散式系統中的旅程



如上圖所示,對開啟延遲讀寫和沒有開啟延遲讀寫做了比較,橫座標為filter過濾的資料,“1”表示沒有過濾,縱軸是花費的時間,實現延遲讀取之後,讀取資料量隨Selectivity的提升而減少,讀取時間也相應大幅降低。

原文連結

本文為雲棲社群原創內容,未經允許不得轉載。


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

相關文章