如何實現Spark on Kubernetes?

阿里技術發表於2020-10-09

如何實現Spark on Kubernetes?

阿里妹導讀:大資料時代,以Oracle為代表的資料庫中介軟體已經逐漸無法適應企業數字化轉型的需求,Spark將會是比較好的大資料批處理引擎。而隨著Kubernetes越來越火,很多數字化企業已經把線上業務搬到了Kubernetes之上,並希望在此之上建設一套統一的、完整的大資料基礎架構。那麼Spark on Kubernetes面臨哪些挑戰?又該如何解決?


雲原生背景介紹與思考

“資料湖”正在被越來越多人提起,儘管定義並不統一,但企業已紛紛投入實踐,無論是在雲上自建還是使用雲產品。

阿里雲大資料團隊認為:資料湖是大資料和AI時代融合儲存和計算的全新體系。為什麼這麼說?在資料量爆發式增長的今天,數字化轉型成為IT行業的熱點,資料需要更深度的價值挖掘,因此確保資料中保留的原始資訊不丟失,應對未來不斷變化的需求。當前以Oracle為代表的資料庫中介軟體已經逐漸無法適應這樣的需求,於是業界也不斷地產生新的計算引擎,以便應對大資料時代的到來。企業開始紛紛自建開源Hadoop資料湖架構,原始資料統一存放在物件儲存OSS或HDFS系統上,引擎以Hadoop和Spark開源生態為主,儲存和計算一體。

圖1是基於ECS底座的EMR架構,這是一套非常完整的開源大資料生態,也是近10年來每個數字化企業必不可少的開源大資料解決方案。

如何實現Spark on Kubernetes?

圖1  基於ECS的開源大資料解決方案

主要分為以下幾層:
  • ECS物理資源層,也就是Iaas層。

  • 資料接入層,例如實時的Kafka,離線的Sqoop。

  • 儲存層,包括HDFS和OSS,以及EMR自研的快取加速JindoFS。


  • 計算引擎層,包括熟知的Spark,Presto、Flink等這些計算引擎。

  • 資料應用層,如阿里自研的Dataworks、PAI以及開源的Zeppelin,Jupyter。

每一層都有比較多的開源元件與之對應,這些層級組成了最經典的大資料解決方案,也就是EMR的架構。我們對此有以下思考:
  • 是否能夠做到更好用的彈性,也就是客戶可以完全按照自己業務實際的峰值和低谷進行彈性擴容和縮容,保證速度足夠快,資源足夠充足。

  • 不考慮現有狀況,看未來幾年的發展方向,是否還需要支援所有的計算引擎和儲存引擎。這個問題也非常實際,一方面是客戶是否有能力維護這麼多的引擎,另一方面是某些場景下是否用一種通用的引擎即可解決所有問題。舉個例子來說,Hive和Mapreduce,誠然現有的一些客戶還在用Hive on Mapreduce,而且規模也確實不小,但是未來Spark會是一個很好的替代品。

  • 儲存與計算分離架構,這是公認的未來大方向,存算分離提供了獨立的擴充套件性,客戶可以做到資料入湖,計算引擎按需擴容,這樣的解耦方式會得到更高的價效比。

基於以上這些思考,我們考慮一下雲原生的這個概念,雲原生比較有前景的實現就是Kubernetes,所以有時候我們一提到雲原生,幾乎就等價於是Kubernetes。隨著Kubernetes的概念越來越火,客戶也對該技術充滿了興趣,很多客戶已經把線上的業務搬到了Kubernetes之上,並且希望在這種類似作業系統上,建設一套統一的、完整的大資料基礎架構。所以我們總結為以下幾個特徵:
  • 希望能夠基於Kubernetes來包容線上服務、大資料、AI等基礎架構,做到運維體系統一化。

  • 存算分離架構,這個是大資料引擎可以在Kubernetes部署的前提,未來的趨勢也都在向這個方向走。

  • 透過Kubernetes的天生隔離特性,更好的實現離線與線上混部,達到降本增效目的。

Kubernetes生態提供了非常豐富的工具,我們可以省去很多時間搞基礎運維工作,從而可以專心來做業務。

EMR計算引擎 on ACK

圖2是EMR計算引擎 on ACK的架構。ACK就是阿里雲版本的Kubernetes,在相容社群版本的API同時,做了大量的最佳化。在本文中不會區分ACK和Kubernetes這兩個詞,可以認為代表同一個概念。

如何實現Spark on Kubernetes?

圖2 計算引擎Kubernetes化

基於最開始的討論,我們認為比較有希望的大資料批處理引擎是Spark和Presto,當然我們也會隨著版本迭代逐步的加入一些比較有前景的引擎。

EMR計算引擎提供以Kubernetes為底座的產品形態,本質上來說是基於CRD+Operator的組合,這也是雲原生最基本的哲學。我們針對元件進行分類,分為service元件和批處理元件,比如Hive Metastore就是service元件,Spark就是批處理元件。

圖中綠色部分是各種Operator,技術層面在開源的基礎上進行了多方面的改進,產品層面針對ACK底座進行了各方面的相容,能夠保證使用者在叢集中很方便的進行管控操作。右邊的部分,包括Log、監控、資料開發、ECM管控等元件,這裡主要是整合了阿里雲的一些基礎設施。我們再來看下邊的部分:
  • 引入了JindoFS作為OSS快取加速層,做計算與儲存分離的架構。

  • 打通了現有EMR叢集的HDFS,方便客戶利用已有的EMR叢集資料。

  • 引入Shuffle Service來做Shuffle 資料的解耦,這也是EMR容器化區別於開源方案的比較大的亮點,之後會重點講到。

這裡明確一下,由於本身Presto是無狀態的MPP架構,在ACK中部署是相對容易的事情,本文主要討論Spark on ACK的解決方案。

Spark on Kubernetes的挑戰

整體看,Spark on Kubernetes面臨以下問題:
  • 我個人認為最重要的,就是Shuffle的流程,按照目前的Shuffle方式,我們是沒辦法開啟動態資源特性的。而且還需要掛載雲盤,雲盤面臨著Shuffle資料量的問題,掛的比較大會很浪費,掛的比較小又支援不了Shuffle Heavy的任務。

  • 排程和佇列管理問題,排程效能的衡量指標是,要確保當大量作業同時啟動時,不應該有效能瓶頸。作業佇列這一概念對於大資料領域的同學應該非常熟悉,他提供了一種管理資源的檢視,有助於我們在佇列之間控制資源和共享資源。

  • 讀寫資料湖相比較HDFS,在大量的Rename,List等場景下效能會有所下降,同時OSS頻寬也是一個不可避免的問題。

針對以上問題,我們分別來看下解決方案。

Spark on Kubernetes的解決方案

Remote Shuffle Service架構

Spark Shuffle的問題,我們設計了Shuffle 讀寫分離架構,稱為Remote Shuffle Service。首先探討一下為什麼Kubernetes不希望掛盤呢,我們看一下可能的選項:

  • 如果用是Docker的檔案系統,問題是顯而易見的,因為效能慢不說,容量也是極其有限,對於Shuffle過程是十分不友好的。

  • 如果用Hostpath,熟悉Spark的同學應該知道,是不能夠啟動動態資源特性的,這個對於Spark資源是一個很大的浪費,而且如果考慮到後續遷移到Serverless K8s,那麼從架構上本身就是不支援Hostpath的。

  • 如果是Executor掛雲盤的PV,同樣道理,也是不支援動態資源的,而且需要提前知道每個Executor的Shuffle資料量,掛的大比較浪費空間,掛的小Shuffle資料又不一定能夠容納下。

所以Remote Shuffle架構針對這一痛點、對現有的Shuffle機制有比較大的最佳化,圖3中間有非常多的控制流,我們不做具體的討論。主要來看資料流,對於Executor所有的Mapper和Reducer,也就是圖中的藍色部分是跑在了K8s容器裡,中間的架構是Remote Shuffle Service,藍色部分的Mapper將Shuffle資料遠端寫入service裡邊,消除了Executor的Task對於本地磁碟的依賴。Shuffle Service會對來自不同Mapper的同一partition的資料進行merge操作,然後寫入到分散式檔案系統中。等到Reduce階段,Reducer透過讀取順序的檔案,可以很好地提升效能。這套系統最主要的實現難點就是控制流的設計,還有各方面的容錯,資料去重,元資料管理等等工作。

如何實現Spark on Kubernetes?

圖3 Remote Shuffle Service架構圖

簡而言之,我們總結為以下3點:
  • Shuffle資料透過網路寫出,中間資料計算與儲存分離架構

  • DFS 2副本,消除Fetch Failed引起的重算,Shuffle Heavy作業更加穩定

  • Reduce階段順序讀磁碟,避免現有版本的隨機IO,大幅提升效能

Remote Shuffle Service效能

我們在這裡展示一下關於效能的成績,圖4和圖5是Terasort Benchmark。之所以選取Terasrot這種workload來測試,是因為它只有3個stage,而且是一個大Shuffle的任務,大家可以非常有體感的看出關於Shuffle效能的變化。

圖4中,藍色部分是Shuffle Service版本的執行時間,橙色部分是原版Shuffle的執行時間。我們測試了2T,4T,10T的資料,可以觀察到隨著資料量越來越大,Shuffle Service優勢就越來越明顯。圖5紅框部分說明了作業的效能提升主要體現在Reduce階段,可見10T的Reduce Read從1.6小時下降到了1小時。原因前邊已經解釋的很清楚了,熟悉Spark shuffle機制的同學知道,原版的sort shuffle是M*N次的隨機IO,在這個例子中,M是12000,N是8000,而Remote Shuffle就只有N次順序IO,這個例子中是8000次,所以這是提升效能的根本所在。

如何實現Spark on Kubernetes?

圖4 Remote Shuffle Service效能

如何實現Spark on Kubernetes?

如何實現Spark on Kubernetes?

圖5 Terasort作業的stage圖

其他方面的重點最佳化

這裡講一下EMR在其他方面做的最佳化。

排程效能最佳化,我們解決了開源的Spark Operator的一些不足,對於Executor pod的很多配置Spark Operator把他做到了Webhook裡邊,這個對排程來說是十分不友好的,因為相當於在API Server上繞了一圈,實際測試下來效能損耗很大。我們把這些工作直接做到Spark核心裡邊,這樣避免了這方面的排程效能瓶頸。然後從排程器層面上,我們保留了兩種選擇給客戶,包括ACK提供的Scheduler FrameworkV2實現方式和Yunicorn實現方式。

讀寫OSS效能最佳化,我們這裡引入了JindoFS作為快取,解決頻寬問題,同時EMR為OSS場景提供了Jindo Job Committer,專門最佳化了job commit的過程,大大減少了Rename和List等耗時操作。

針對Spark本身,EMR積累了多年的技術優勢,也在TPCDS官方測試中,取得了很好的成績,包括Spark效能、穩定性,還有Delta lake的最佳化也都有整合進來。

我們提供了一站式的管控,包括Notebook作業開發,監控日誌報警等服務,還繼承了NameSpace的ResourceQuota等等。

總體來說,EMR版本的Spark on ACK,無論在架構上、效能上、穩定性上、易用性方面都有著很大的提升。

Spark雲原生後續展望

從我的視角來觀察,Spark雲原生容器化後續的方向,一方面是達到運維一體化,另一方面主要希望做到更好的價效比。我們總結為以下幾點:
  • 可以將Kubernetes計算資源分為固定叢集和Serverless叢集的混合架構,固定叢集主要是一些包年包月、資源使用率很高的叢集,Serverless是做到按需彈性。

  • 可以透過排程演算法,靈活的把一些SLA不高的任務排程到Spot例項上,就是支援搶佔式ECI容器,這樣可以進一步降低成本。

  • 由於提供了Remote Shuffle Service叢集,充分讓Spark在架構上解耦本地盤,只要Executor空閒就可以銷燬。配合上OSS提供的存算分離,必定是後續的主流方向。

  • 對於排程能力,這方面需要特別的增強,做到能夠讓客戶感受不到效能瓶頸,短時間內排程起來大量的作業。同時對於作業佇列管理方面,希望做到更強的資源控制和資源共享。

如何實現Spark on Kubernetes?

圖6 Spark on Kubernetes混合架構

隨著阿里雲2.0時代的到來,雲原生已經逐漸成為新的主角,越來越多的企業將會享受到雲原生所帶來的紅利。資料湖計算引擎雲原生容器化,能夠極大地方便客戶上雲,提升價效比。但是整體上來講:大資料雲原生的落地是十分具有挑戰性的,阿里雲EMR團隊會和社群同伴、合作伙伴一起打造技術和生態,共同打造“存算分離,按需擴充套件”、“極致彈性,隨用隨得”、“運維閉環,高價效比”的願景。

相關文章