Spark on k8s在阿里雲EMR的優化實踐
導讀: 隨着大數據技術的發展,Spark 成為當今大數據領域最受關注的計算引擎之一。在傳統的生產環境中,Spark on YARN 成為主流的任務執行方式,而隨着容器化概念以及存算分離思想的普及,尤其是 Spark3.1 版本下該模式的正式可用(GA),Spark on K8s 已成燎原之勢。
今天的介紹會圍繞下面兩點展開:
- Spark on K8s 的基礎概念和特性
- Spark on K8s 在阿里雲 EMR 的優化和最佳實踐
點擊查看直播回放
Spark on K8s 的基礎概念和特性
首先和大家分享下 Spark on K8s 的一些背景。
1. Spark 的集群部署模式
Spark 現如今支持 4 種部署模式:
- Standalone:使用 Spark 的內置調度器,一般用於測試環境,因為沒有充分利用到大數據的調度框架,無法充分利用集群資源。
- Hadoop YARN:最常見的一種方式,源自 Hadoop,擁有良好的社區生態。
- Apache Mesos:與 YARN 類似,也是一個資源管理框架,現在已經逐漸退出歷史舞台。
- Kubernetes:即 Spark on K8s,Spark3.1.1 對這種部署模式正式提供可用支持,越來越多的用戶也在積極做這方面的嘗試。
使用 Spark on K8s 的優勢如下:
- 提高資源利用率:無需按照使用場景部署多個集群,所有 Spark 作業共享集群資源,能提高總體集群利用率,而且在雲上使用時可以彈性容器實例,真正做到按量付費。
- 統一運維方式:可以利用 K8s 的社區生態和工具,統一維護集群,減少集群切換帶來的運維成本。
- 容器化:通過容器鏡像管理,提高 Spark 任務的可移植性,避免不同版本 Spark 帶來版本衝突問題,支持多版本的 A/B Test。
尤其需要關注的一點是,根據我們的測試,在相同的集群資源條件下,Spark on K8s 和 Spark on YARN 的性能差距幾乎可以忽略不計。再加上充分利用 Spark on K8s 的彈性資源,可以更好地加速 Spark 作業。
總結來看,Spark on K8s 相較於 Spark on YARN 的模式來說,其實是利大於弊的。
2. Spark on K8s 的部署架構
當前環境下,想要把 Spark 作業提交到 K8s 上,有兩種方式:
- 使用原生的 spark-submit
在這種方式下,K8s 集群無需提前安裝組件。像現在使用的 YARN 的提交方式一樣,提交作業的 Client 端需要安裝 Spark 的環境,並且配置 kubectl,就是連接 K8s 集群的一個工具,然後在提交命令中標註 K8s 集群地址以及使用的 Spark 鏡像地址即可。
上圖詳細的展示了使用原生的 spark-submit 提交任務到 K8s 的任務運行流程。用戶在 Client 端執行 spark-submit 命令後會在本地啟動一個進程,該進程會連接 K8s 的 api server 請求創建一個 Driver Pod。Driver Pod 在啟動進程中會啟動 Spark Context,並負責申請 Executor Pod。任務執行完畢後,Driver Pod 會負責清理 Executor Pod。但 Driver Pod 結束後會保留,用於日誌或狀態的查看,需要手動清理。
優點:
這種提交方式符合用戶的使用習慣,減少用戶學習成本,與現有的大數據平台集成性更好。因為是 Client 模式提交,支持本地依賴,支持 Spark-shell 的交互式作業模式。
- 使用 Spark-on-K8s-operator
Spark-on-K8s-operator 是 Google 開源的一個組件,需要提前在 K8s 集群中部署一個常駐 pod,以提供相關服務。與第一種方式不同的是,使用這種方式不再是以命令行的方式提交,而是使用 kubectl 提交一種 yaml 文件來提交作業。本質上來說,這種工具具體實現還是使用的 spark-submit 的方式,只是相當於命令行中的信息換了一種格式以文件的形式提交。但是 Spark-on-K8s-operator 在第一種方式的基礎上,做了一些輔助工具,包括定時調度、監控、作業管理等。
從流程上來說,用戶提交了一個 yaml 文件,在 K8s 集群上常駐的 Spark-on-K8s-operator 就監聽到了這個事件,通過解析文件轉化成執行 spark-submit 命令啟動一個 Spark 任務。
除了提交方式的不同,我們剛剛也提到這個工具提供了一些輔助的功能。Spark-on-K8s-operator 通過 K8s 的 Mutating Admission Webhook 機制,攔截了 K8s 的 Api 請求,在啟動 Driver 和 Executor Pod 資源時,可以對其進行一些自定義配置處理。另一方面,工具可以監聽 Driver 和 Executor Pod 的事件,從而跟蹤和管理任務的執行進度。
優點:
工具的存在支持作業的管理,包括記錄、重試、定時執行等。提供作業監控指標,也可以對接 Prometheus 方便統一監控。支持自動清理作業資源,也可以自動配置 Spark UI 的 service/ingress。
3. Spark on K8s 的社區進展
Spark2.3 之前,有人嘗試過通過在 K8s 上部署 YARN 的方式來支持 Spark on K8s,但是本質上 Spark 還是跑在 YARN 的資源管控下,所以並不能稱之為完整意義上的 Spark on K8s。
Spark2.3,社區首次發佈支持了原生的 Spark on K8s,全是第一次官方支持這樣的部署方式。
Spark2.4 做了少量的特性優化,真正完善了這個功能是在 Spark3 版本,尤其是 Spark3.1 正式可用(GA)。當前 Spark on K8s 方向熱度很高,所以如果感興趣的同學建議直接升級到 Spark3.1 來嘗試這個部署方式。
4. Spark on K8s 的重點特性
- 優化 Spark Pod 配置屬性
K8s 的 Pod 定義通常採用 Yaml 的描述處理,早期的 Driver 和 Executor Pod 定義只能通過 Spark Conf 進行配置,靈活性很差,畢竟不是所有的配置都能通過 Spark Conf 處理。Spark3.0 開始,支持使用模板文件。用戶可以建立模板文件,定義 Pod 的屬性,然後通過 spark 的配置傳入,相較於單條配置更加便利,靈活性增強了很多。
- 動態資源分配(Dynamic Allocation)
Spark2 版本時,動態資源分配只能使用 External Shuffle Service(ESS)的方式,這種方式下,executor 在執行時產生的 shuffle 數據全部交由 ESS 服務接管,executor 執行完畢隨時回收。但是這種方式一般由 YARN 的 Node Manager 啟動管理,很難在 K8s 上部署。
Spark3 版本中支持了 Shuffle Tracking 的特性,就是可以在沒有 ESS 的情況下,利用自身對 executor 的管理,做到動態資源配置的效果。但是這種方式的缺點就是,在 shuffle read 階段 executor 不能動態回收,仍需要保留以供 reducer 讀取 shuffle 數據,然後需要等到 driver 端 gc 之後才會標記這個 executor 可以釋放,資源釋放效率低。
- 節點優雅下線(node decommissioning)
在 K8s 的環境中,節點的縮容,搶佔式實例回收這些場景還是比較常見的,尤其是在一些場景下,將部分 Spark 的任務優先級調低以滿足其他高優先級的任務的使用。這種場景下,executor 直接退出可能會存在 stage 重算等情況,延長了 Spark 的執行時間。Spark3.1 提供了「優雅下線」特性,支持 Executor Pod 在「被迫」下線前,可以通知 Driver 不再分配新的 Task,並將緩存的數據或者 shuffle 的文件遷移到其他的 Executor Pod 中,從而保證對應 Spark 任務的效率,避免重算。
當前這個功能還屬於實驗性質,也就是默認不開啟。
- PersistentVolumeClaim 復用
PersisentVolumnClaim(簡稱 pvc),是 K8s 的存儲聲明,每個 Pod 都可以顯式地申請掛載。Spark3.1 支持動態創建 pvc,意味着不需要提前聲明申請,可以隨着執行動態的申請掛載資源。但是這個時候 pvc 的生命周期伴隨着 Executor,如果出現上述的搶佔式被迫關閉的情況,同樣會出現保存在 pvc 上面的數據丟失重算的問題。所以在 Spark3.2 中,支持了 pvc 重新利用,它的生命周期伴隨 Driver,避免了重新申請和計算,保障整體的效率。
Spark on K8s 在阿里雲 EMR 的優化和最佳實踐
接下來和大家分享下阿里雲 EMR 對於 Spark on K8s 的優化和最佳實踐。
1. Spark on ACK 簡介
ACK:阿里雲容器服務 Kubernetes 版,簡稱 ACK。
EMR:阿里雲開源大數據平台 E-MapReduce,簡稱 EMR。
在阿里雲公共雲上,我們有一款 EMR on ACK 的產品,其中包含了 Spark 類型的集群,後面簡稱 Spark on ACK。Spark on ACK 這個產品是一套半託管的大數據平台,用戶首先需要有一個自己的 ACK 集群,也就是 k8s 集群,然後我們會在這個集群內創建一個用於 Spark 作業的 namespace,並安裝一些固定組件 pod 比如 spark-operator、historyserver 之類,後續的 Spark 作業 pod 也會在這個 namespace 下運行,這些 Spark 作業 pod 可以利用用戶自己的 ACK 節點機器來跑,也可以利用我們的彈性實例 ECI 來跑,來實現按量付費。這個所謂彈性實例 ECI 是什麼,接下來我們具體介紹一下。
2. 雲上彈性優勢
Spark 在雲上最大的優勢就是更好的彈性,在阿里雲的 ACK 的環境中,提供了一個彈性容器實例 ECI 的產品,有了 ECI 意味着,我們申請 pod 時不再是佔用自己的機器節點的資源了,而是完全利用雲上資源來創建 pod,而且可以做到快速拉起,秒級付費。利用 ECI 來跑 spark 作業我認為是非常划算的,因為通常大家用 spark 作業跑批處理任務,凌晨高峰,白天可能只有少量查詢,這種峰谷明顯的特點搭配快速彈性和按量付費是很適合的,外加 ECI 可以使用 spot 搶佔式實例,有 1 個小時的保護期,並結合 Spark 的 Node decommissioning 特性,可以節省很多成本。
3. RSS 優化 Shuffle 和動態資源
Spark Shuffle 對本地存儲依賴較大,但是雲上環境下,存儲分離的機器很難保障自帶本地磁盤,使用雲盤大小也無法預估,性價比不高。另一方面,Spark 原生的無 ESS 的動態資源配置,executor 的釋放資源效率較低,可能因為無法回收造成資源浪費。
Spark Shuffle 本身也有很多缺點。Mapper 的輸出量增大,導致 spill 到本地磁盤,引發額外的 IO;Reducer 並發拉取 Mapper 端的數據,導致大量隨機讀的產生,降低效率;在 shuffle 過程中,產生 numMapper * numReducer 個網絡連接,消耗過多 CPU 資源,帶來性能和穩定性問題;Shuffle 數據單副本導致數據丟失時,需要重新計算,浪費資源。
阿里雲提供了獨立部署的 RSS,目前已經在 github 上開源,可以直接對接 ACK,用戶無需關注 Shuffle 數據是否有本地磁盤支持。原先的 spark shuffle 數據保存在 executor 本地磁盤,使用 RSS 後,shuffle 的數據就交給 RSS 來管理了。其實採用 push based 的外部 shuffle service 業界已經是一種共識了,很多公司都在做這方面的優化。優點有很多,Executor 執行完畢即可回收,節約資源;RSS 還將傳統的大量隨機讀優化成了追加寫,順序讀,進一步彌補了 Spark Shuffle 的效率問題;RSS 服務支持 HA 部署,多副本模式,降低重複計算的可能性,進一步保障 Spark 任務的效率。
4. 增強 K8s 作業級別調度
K8s 默認的調度器調度粒度是 Pod,但是傳統的 Spark 任務調度默認粒度是 application。一個 Application 的啟動,會伴隨啟動多個 Pod 執行支持。所以,突然提交大量 Spark 任務時,可能出現大量 Driver Pod 啟動,單都在等待 Executor Pod 啟動,從而導致整個集群死鎖。另一方面,K8s 的多租戶場景支持不佳,也不支持租戶之間的彈性調度,以及動態配額等。相比於 YARN 的調度策略,K8s 的調度策略單一,為默認優先級+FIFO 的方式,無法做到公平調度。
阿里雲 ACK 在這個方面做了增強:
- 調度時優先判斷資源是否滿足,解決上述可能出現的死鎖問題。
- 基於 NameSpace 實現多租戶樹狀隊列,隊列可以設置資源上下限,支持隊列間搶佔資源。
- 實現了以 App 粒度調度 Spark 作業的優先級隊列,支持隊列間的公平。調度,並基於 Spark-on-K8s-operator 的擴展,提交作業會自動進入隊列。
5. 雲上數據湖存儲與加速
- 在 K8s 環境下,相比於傳統的 Hadoop 集群,使用數據湖存儲 OSS 更貼合存算分離的架構。Spark on ACK 內置 Jindo SDK,無縫對接 OSS。
- Fluid 可支撐 Spark on K8s 部署模式下的緩存加速,在 TPC-DS 場景下,可以提升運行速度 30%左右。
6. 使用 DLF 構建雲上數據湖
在 K8s 上想要使用 Hadoop 生態圈的組件,還需要額外部署。但是 Spark on ACK 無縫對接阿里雲 DLF(Data Lake Formation),DLF 提供了統一的元數據服務,支持權限控制和審計,另外提供數據入湖的功能,支持 Spark SQL 的交互式分析,以及數據湖管理功能,支持進行存儲分析和成本優化。
7. 易用性提升
Spark on ACK 提供了一個 CLI 工具,可以直接以 spark-submit 語法來提交 spark 作業,同時也會記錄到 spark-operator 裏面來管理。之前我們提到了 2 種提交作業方式的優劣,spark-operator 具備比較好的作業管理能力,但是提交作業不兼容老的命令語法,也無法跑交互式 shell,從老集群遷移的用戶改動比較麻煩,因此利用我們這種工具,可以同時享受 2 種提交方式的優點,對用戶的易用性來說是個比較大的提升。
在日誌收集這一點,Spark on ACK 提供日誌收集方案,並通過 HistoryServer 讓用戶可以像 Spark on YARN 一樣在界面上查看。