偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Spark on K8s 在 vivo 大數(shù)據(jù)平臺(tái)的混部實(shí)戰(zhàn)

大數(shù)據(jù)
在離線混部可以提高整體的資源利用率,不過離線Spark任務(wù)部署到混部容器集群需要做一定的改造,本文將從在離線混部中的離線任務(wù)的角度,講述離線任務(wù)是如何進(jìn)行容器化、平臺(tái)上的離線任務(wù)如何平滑地提交到混部集群、離線任務(wù)在混部集群中如何調(diào)度的完整實(shí)現(xiàn)以及過程中的問題解決。

一、在離線業(yè)務(wù)差異

互聯(lián)網(wǎng)數(shù)據(jù)業(yè)務(wù)服務(wù)一般可以分為在線服務(wù)和離線任務(wù)兩大類,在線服務(wù)是指那些長(zhǎng)時(shí)間運(yùn)行、隨時(shí)響應(yīng)對(duì)實(shí)時(shí)性要求高、負(fù)載壓力隨著接收流量起伏的服務(wù),如電商、游戲等服務(wù),離線任務(wù)是指運(yùn)行周期短、可執(zhí)行時(shí)間提交對(duì)實(shí)時(shí)性要求低、有一定容錯(cuò)性、負(fù)載壓力基本可控的服務(wù),如離線計(jì)算任務(wù)、模型訓(xùn)練等。一般在線服務(wù)在白天時(shí)段繁忙,離線任務(wù)在凌晨繁忙,兩者的業(yè)務(wù)高峰期存在錯(cuò)峰現(xiàn)象,如果按傳統(tǒng)方式在線和離線都是分別獨(dú)立機(jī)器部署,業(yè)務(wù)高峰時(shí)期需要更多機(jī)器來支持,業(yè)務(wù)低峰期又存在部分機(jī)器空閑,整體資源利用率都不高。因此行業(yè)提出來在離線混部的解決方案,在線和離線業(yè)務(wù)通過混部系統(tǒng)部署在同一批機(jī)器,實(shí)現(xiàn)共享資源并錯(cuò)峰互補(bǔ),提高整體的資源利用率。目前業(yè)內(nèi)利用混部技術(shù)可以將數(shù)據(jù)中心的CPU利用率提升至40%左右,vivo在2023年混部平臺(tái)投入生產(chǎn)也已經(jīng)將部分混部集群的CPU利用率提升至30%左右,整體收益也是可觀的。

混部系統(tǒng)需要有強(qiáng)大的隔離能力,絕大部分都是基于容器,所以混部的前提是在線和離線業(yè)務(wù)都容器化,對(duì)于容器管理工具如K8s來說是更適應(yīng)于運(yùn)行時(shí)間長(zhǎng)、啟停次數(shù)少、容器數(shù)量少的在線服務(wù),在線服務(wù)也能比較容易地上容器,而對(duì)于運(yùn)行時(shí)間短、啟停頻繁、容器數(shù)量大的離線任務(wù),對(duì)K8s來說不是天然地適應(yīng),但容器化已是大勢(shì)所趨,K8s也推出了性能更好的調(diào)度器、用于離線任務(wù)的控制器,Spark在2.3版本后也支持容器化,諸多技術(shù)的發(fā)展也推動(dòng)離線任務(wù)實(shí)現(xiàn)容器化以及在離線混部的落地。

本文將從在離線混部中的離線任務(wù)的角度,講述離線任務(wù)是如何進(jìn)行容器化、平臺(tái)上的離線任務(wù)如何平滑地提交到混部集群、離線任務(wù)在混部集群中如何調(diào)度的完整實(shí)現(xiàn)以及過程中的問題解決。

二、離線任務(wù)容器化

2.1 Spark Operator 方案

2.1.1 方案對(duì)比

vivo離線任務(wù)大部分任務(wù)是以Spark作為執(zhí)行引擎,Spark任務(wù)運(yùn)行在K8s上,目前業(yè)界有兩種架構(gòu)的方案:Spark on K8s及Yarn on K8s。兩者部分優(yōu)缺點(diǎn)對(duì)比如下:

圖片

Spark on K8s是Spark容器化,由K8s直接創(chuàng)建Driver和Executor的Pod來運(yùn)行Spark作業(yè),Yarn on K8s是Yarn的容器化,由K8s創(chuàng)建RM和NM的Pod,Spark的Driver和Executor運(yùn)行在NM Pod的container中,正是由于兩種架構(gòu)方案的區(qū)別,它們各自也會(huì)存在優(yōu)缺點(diǎn)。

Yarn on K8s方案可以支持原生的Hive、Spark、Flink等引擎,它僅需要?jiǎng)?chuàng)建一定數(shù)量的NodeManager Pod來滿足作業(yè)需求,Pod運(yùn)行相對(duì)穩(wěn)定因此對(duì)K8s的壓力比較小,本身Yarn支持調(diào)度性能和調(diào)度策略也是專門為離線任務(wù)設(shè)計(jì)的,調(diào)度性能比K8s的強(qiáng)很多。由于NodeManager ESS服務(wù)是對(duì)磁盤有容量和讀寫性能要求的,混部機(jī)器的磁盤一般難以滿足,所以也需要能支持不同引擎的Remote Shuffle Service。在資源利用上,NodeManager需要滿足多個(gè)作業(yè)的資源,最小單位是Container,Pod的資源粒度比較大,自身也會(huì)占用一些資源,如果資源粒度得不到有效地彈性伸縮,也會(huì)造成資源的浪費(fèi),因此需要引入額外的組件來協(xié)調(diào),根據(jù)Kubernetes集群節(jié)點(diǎn)的剩余資源,動(dòng)態(tài)調(diào)整NodeManager的CPU和內(nèi)存,然而這也需要一定的改造成本。在資源緊張的情況下,NodeManager Pod如果被驅(qū)逐也就意味著整個(gè)NodeManager被銷毀,將會(huì)影響多個(gè)任務(wù)。

Spark on K8s方案目前在Spark 3.1以上版本才正式可用,它需要頻繁的創(chuàng)建、查詢、銷毀大量的Executor Pod,對(duì)K8s的ApiServer和ETCD等組件都會(huì)造成比較大的壓力,K8s的調(diào)度器也不是專門為離線的大批量任務(wù)設(shè)計(jì)的,調(diào)度性能也比較弱。另一方面,Spark on K8s雖然只能支持Spark3.X的RSS,不過目前有較多的開源產(chǎn)品可選擇。在資源利用上,最小單位是Driver和Executor的Pod,資源粒度小,可以填充到更多的碎片資源,調(diào)度時(shí)直接與K8s對(duì)接,資源的彈性調(diào)度更多由K8s來承擔(dān),不需要額外的組件,改造成本比較低。在資源緊張的情況下,Executor、Driver的Pod將依次逐個(gè)被驅(qū)逐,任務(wù)的穩(wěn)定性會(huì)更高。

而對(duì)于Spark on K8s方案,還細(xì)分2種實(shí)現(xiàn)方案:Spark Submit on K8s和Spark Operator on K8s。

圖片

SparkOnK8s架構(gòu)圖

(圖片來源:Spark官網(wǎng))?

圖片

Spark Operator架構(gòu)圖

(圖片來源:Spark Operator開源項(xiàng)目)

以spark-submit方式提交到K8s集群是Spark在2.3版本后提供的原生功能,客戶端通過spark-submit設(shè)置K8s的相關(guān)參數(shù),內(nèi)部再調(diào)用K8sApi在K8s集群中創(chuàng)建Driver Pod,Driver再調(diào)用K8sApi創(chuàng)建需要的Executor Pod,共同組成Spark Application,作業(yè)結(jié)束后Executor Pod會(huì)被Driver Pod銷毀,而Driver Pod則繼續(xù)存在直到被清理。使用spark-submit方式的最大好處是由spark-submit來與K8s的進(jìn)行交換,提交作業(yè)的方式幾乎保持一致。但是因?yàn)槭褂玫谋憷运枰姆庋b也會(huì)帶來一些缺點(diǎn),spark-submit是通過K8sApi創(chuàng)建Pod,使用非聲明式的提交接口,如果需要修改K8s配置就需要重新開發(fā)新接口,二次開發(fā)復(fù)雜繁瑣,雖然Spark提供了大量的K8s配置參數(shù),但也遠(yuǎn)比不了K8s YAML的聲明式的提交方式更加靈活,而且Spark Application和K8s Workload的生命周期還不能較好地對(duì)應(yīng)起來,生命周期不能靈活控制,任務(wù)監(jiān)控也比較難接入Prometheus集群監(jiān)控。雖然Spark社區(qū)也不斷地在推出新特性來和K8s集成地更加靈活,不過對(duì)于些復(fù)雜場(chǎng)景需要定制開發(fā),spark-submit的封裝性也會(huì)成為阻礙。

spark-submit還是離線任務(wù)提交的思維,而Spark Operator方式就更傾向于K8s作業(yè)的思維,作為K8s的自定義控制器,在集成了原生的Spark on K8s的基礎(chǔ)上利用K8s原生能力提供了更全面管控功能。Spark Operator使用聲明式的YAML提交Spark作業(yè),并提供額外組件來管理Spark作業(yè)的生命周期,SparkApplication控制器,負(fù)責(zé)SparkApplicationObject的創(chuàng)建、更新和刪除,同時(shí)處理各種事件和作業(yè)狀態(tài),Submission Runner, 負(fù)責(zé)調(diào)用spark-submit提交Spark作業(yè),Driver和Executor的運(yùn)行流程是一致的,Spark Pod Monitor,負(fù)責(zé)監(jiān)控和同步Spark作業(yè)相關(guān)Pod的狀態(tài)。Spark Operator最大的好處是為在K8s中的Spark作業(yè)提供了更好的控制、管理和監(jiān)控的功能,可以更加緊密地與K8s結(jié)合并能靈活使用K8s各種特性來滿足復(fù)雜場(chǎng)景,例如混部場(chǎng)景,而相對(duì)地它也不再像spark-submit那樣方便地提交任務(wù),所以如何使用Spark Operator優(yōu)雅提交任務(wù)將是在離線混部中一項(xiàng)重要的工作。

2.1.2 最終選項(xiàng)

在大的架構(gòu)選型上,我們選擇了Spark on K8s,一方面因?yàn)镾park3.X是vivo當(dāng)前及未來2~3年的主流離線引擎,另一方面vivo有比較完善的K8s生態(tài)體系,內(nèi)部對(duì)K8s研發(fā)也比較深入,環(huán)境和能力都能很好地支持,在應(yīng)用的小方向上,我們選擇了Spark Operator,因?yàn)樗诨觳窟@種復(fù)雜場(chǎng)景下使用更加靈活、擴(kuò)展性更強(qiáng)、改造成本更低,我們最終決定使用Spark Operator方案。

2.2 Spark優(yōu)化

2.2.1 Spark鏡像

Spark任務(wù)容器化的第一步就是構(gòu)建具有Spark相關(guān)環(huán)境的鏡像,Spark任務(wù)類型主要分為sql任務(wù)和jar任務(wù),在實(shí)踐的過程中我們發(fā)現(xiàn)Spark的鏡像構(gòu)建需要注意幾個(gè)問題

  • Spark環(huán)境的完整性:鏡像中除了打入自研的Spark包以外,還需要打入相應(yīng)的依賴如Hadoop、ZSTD、RSS等包,對(duì)于SparkJar任務(wù)還有直接調(diào)用Hadoop客戶端的,因此Hadoop客戶端也需要打入鏡像中。
  • JDK版本問題:K8s使用的Spark是基于3.2.0版本,鏡像打包工具默認(rèn)使用JDK11,而自研的Spark用的JDK1.8,由于在Yarn和K8s上使用的JDK版本不同,導(dǎo)致在雙跑驗(yàn)證數(shù)據(jù)一致性時(shí)發(fā)現(xiàn)了hash函數(shù)、時(shí)間戳不一致的問題,因此Spark鏡像中的JDK版本需要和Yarn保持一致。
  • 環(huán)境變量問題:鏡像生成容器后需要預(yù)置如Spark、Hadoop的環(huán)境變量,如果鏡像中相關(guān)目錄的位置不能完全和Yarn的提交節(jié)點(diǎn)保持一致,則需要檢查各啟動(dòng)腳本,如spark-env.sh中的環(huán)境變量的路徑是否存在,發(fā)生沖突時(shí)可以修改為絕對(duì)路徑。

Spark鏡像構(gòu)建完成后,區(qū)分SparkSql任務(wù)和SparkJar任務(wù)實(shí)質(zhì)就是啟動(dòng)命令的不同,事實(shí)上SparkSql任務(wù)也就是SparkJar任務(wù)的一種,只是啟動(dòng)的主類是固定的,兩者的啟動(dòng)參數(shù)如下:

SparkSql任務(wù):

driver --class org.apache.spark.sql.hive.thriftserver.SparkSQLCLIDriver -f {sql文件}

SparkJar任務(wù):

driver --class {jar任務(wù)主類} {jar任務(wù)jar包} {參數(shù)}

早期不僅構(gòu)建了Spark鏡像,還構(gòu)建了Spark日志鏡像,容器組成結(jié)構(gòu)會(huì)復(fù)雜一些。如圖例如Driver容器,我們將Spark、Hadoop等配置文件構(gòu)建了configMap,啟動(dòng)initContainer來拉取從configMap拉取配置文件,然后啟動(dòng)Driver容器執(zhí)行Spark任務(wù),同時(shí)也使用sidecar創(chuàng)建日志上報(bào)的容器,在Spark任務(wù)運(yùn)行完成后上報(bào)Driver和Executor日志到Spark HistoryServer。這樣的方案看似充分應(yīng)用了K8s技術(shù),但是在實(shí)踐的過程中這些技術(shù)卻被一一棄用,轉(zhuǎn)而逐步地把各種功能集中到了一個(gè)Driver容器上。

圖片

具體演進(jìn)如下:

  • 移除initContainer,拉取Spark等配置文件步驟寫在啟動(dòng)命令中,Spark作業(yè)執(zhí)行前執(zhí)行下載配置,原因在多個(gè)namespace下不方便統(tǒng)一管理,而且configmap內(nèi)容較大,會(huì)導(dǎo)致Pod啟動(dòng)時(shí)配置加載的延遲增加,影響了Pod創(chuàng)建速度,同時(shí)K8s的內(nèi)存和CPU資源占用增加,對(duì)kube-apiserver、ETCD負(fù)載有一些影響。去掉initContainer還有個(gè)重要的好處就是減小ETCD的存儲(chǔ)壓力,事實(shí)上我們?cè)谝瞥齣nitContainer拉取配置的功能后的一段時(shí)間內(nèi)還保留著initContainer,在任務(wù)逐漸上量后發(fā)現(xiàn)ETCD的存儲(chǔ)比較滿,分析后發(fā)現(xiàn)Spark作業(yè)中的一個(gè)Pod生命周期大約8次更新,其中initContainer更新會(huì)占用2次,移除了之后理論上是可以減少1/4的ETCD存儲(chǔ),實(shí)際應(yīng)用中完全去除了initContainer也確實(shí)能減小了ETCD的存儲(chǔ)壓力。
  • 移除sidecar創(chuàng)建日志上報(bào)的容器,Driver和Executor日志上報(bào)步驟寫在啟動(dòng)命令中,Spark作業(yè)執(zhí)行完后再執(zhí)行腳本上報(bào),原因是sidecar在同一個(gè)Pod中與主容器共享相同的生命周期,不使用sidecar方式就能更快創(chuàng)建Pod,Spark任務(wù)執(zhí)行完成后能更快釋放資源。

對(duì)于Spark作業(yè)會(huì)頻繁創(chuàng)建、更新和銷毀大量的Pod,所以去除非必要的容器,提高Pod生命周期流轉(zhuǎn)速度,就能降低kube-apiserver、ETCD工作負(fù)載,也能提高Spark的作業(yè)效率。

2.2.2 Spark改造

Spark任務(wù)運(yùn)行在K8s上,對(duì)于一些使用的兼容問題也進(jìn)行了相關(guān)改造。

  • HistoryServer改造,因?yàn)镾park Operator沒有存儲(chǔ)已結(jié)束作業(yè)的日志,因此參考了on Yarn的方式,在Spark作業(yè)結(jié)束后,通過日志上傳腳本把Driver和Executor的日志上傳HDFS,與Yarn日志聚合類似,同時(shí)也在Spark HistoryServer做了二次開發(fā)工作,增加了on K8s方式的日志查看接口,用戶查看已完成的Executor日志時(shí),不再請(qǐng)求JobHistory Server,而是請(qǐng)求Spark HistoryServer接口。但日志上傳方式需要Executor執(zhí)行完才能查看到日志,為了能實(shí)時(shí)查看到執(zhí)行中的日志,可以在Executor內(nèi)部實(shí)現(xiàn)一個(gè)HTTP服務(wù),根據(jù)Pod以及端口信息拼接出日志請(qǐng)求URL,Executor啟動(dòng)一個(gè)Servlet自動(dòng)獲取本地日志并返回。日志查看體驗(yàn)上做到了基本與Yarn一致。
  • 主機(jī)ip通信,Spark Driver和Executor之間的通信通常是通過主機(jī)名進(jìn)行的,不過隨著Spark任務(wù)增多,CoreDNS因?yàn)轭l繁的域名解釋請(qǐng)求導(dǎo)致壓力增大,甚至?xí)绊懙皆诰€服務(wù),因此我們將Hadoop的配置文件改為ip格式、設(shè)置Driver和Executor使用ip地址,同時(shí)去除了對(duì)應(yīng)的K8s Service,通過訪問ip而不是域名的方式來規(guī)避這個(gè)問題。
  • 文件參數(shù)兼容,Spark Driver在K8s上是運(yùn)行在某一個(gè)Pod中的,所以文件需要是全局可視的,如HDFS文件,否則就會(huì)報(bào)文件未找到的錯(cuò)誤,但Spark作業(yè)運(yùn)行在大數(shù)據(jù)作業(yè)平臺(tái)時(shí)有的任務(wù)使用的上傳的本地文件,因此對(duì)于提交到K8s的任務(wù),第一步是要把上傳到大數(shù)據(jù)作業(yè)平臺(tái)的文件再次上傳到HDFS,第二步是改造add jar和--file等命令邏輯,Spark任務(wù)在未能讀取本地文件后將再嘗試讀取二次上傳到HDFS的文件,實(shí)現(xiàn)任務(wù)無需修改成全局可視的文件路徑也能讀取到文件。
  • non-daemon線程終止,在K8s上運(yùn)行的Spark任務(wù)是指定Client模式,Client模式下Driver遇到異常時(shí)停掉SparkContxet,等所有non-daemon線程結(jié)束后,Driver才會(huì)退出,但如果存在一直運(yùn)行的non-daemon線程,那么Driver一直不退出,任務(wù)就一直處于執(zhí)行中。因此需要改造成Cluster模式的異常退出機(jī)制,即異常時(shí)以非0退出碼退出,不再等待其他的non-daemon線程結(jié)束,Driver直接終止,以確保Driver Pod的正常結(jié)束。

2.3 Spark Operator優(yōu)化

隨著在K8s上運(yùn)行的Spark任務(wù)不斷增加,K8s集群的負(fù)載也逐漸顯現(xiàn)。因此,需要對(duì)Spark Operator進(jìn)行一系列優(yōu)化,以減輕K8s集群的壓力。

  • 離線使用獨(dú)立的kube-apiserver,混部集群中離線容器占了很大一部分,而且離線任務(wù)由于生命周期短,容器創(chuàng)建銷毀更加頻繁,這對(duì)kube-apiserver造成了很大的壓力,然而在線業(yè)務(wù)需要更高的穩(wěn)定性,為了減少離線對(duì)在線業(yè)務(wù)的影響,我們拆分了kube-apiserver,離線任務(wù)通過指定master參數(shù)來使用獨(dú)立的kube-apiserver。
  • 使用K8s的HostNetwork網(wǎng)絡(luò)模式在K8s上啟動(dòng)Driver與Executor雖然使用的是獨(dú)立ip+固定端口,但頻繁的ip申請(qǐng)和釋放也對(duì)kube-apiserver造成了一定的壓力,因此我們改為使用HostNetwork網(wǎng)絡(luò)模式,同時(shí)不指定端口避免端口沖突。
  • 優(yōu)化Spark Operator控制器的隊(duì)列,在任務(wù)量比較大的情況下,Spark Operator對(duì)Pod創(chuàng)建消耗效率會(huì)遇到瓶頸,排查后發(fā)現(xiàn)是Spark Operator的事件處理隊(duì)列的并發(fā)數(shù)和限速桶的默認(rèn)配置地太小,因此我們調(diào)低Spark maxPendingPods參數(shù),調(diào)高schedulerBacklogTimeout、 sustainedSchedulerBacklogTimeout參數(shù),減少Pending Pod個(gè)數(shù),使Pod的處理效率符合集群的承載水平。
  • 優(yōu)化Spark Driver List Pod接口,使用kube-apiserver緩存,避免對(duì)ETCD產(chǎn)生影響,同時(shí)修改Spark Driver清理Executor邏輯,直接Delete,減少List Pod對(duì)kube-apiserver壓力。
  • 存儲(chǔ)emptydir + log lv存儲(chǔ)優(yōu)化,開發(fā)CSI插件,Spark任務(wù)的離線日志單獨(dú)存儲(chǔ),避免對(duì)在線業(yè)務(wù)pod的影響和磁盤負(fù)載高等問題。
  • Spark Secret標(biāo)記immutable,減少kubelet watch secret請(qǐng)求,降低kube-apiserver的負(fù)載。

三、離線任務(wù)提交

3.1 平臺(tái)任務(wù)提交平滑切換

離線任務(wù)容器化方案確定后就要落地到生產(chǎn),目前有SparkSql和SparkJar兩種離線任務(wù)實(shí)現(xiàn)了容器化,這里以SparkSql任務(wù)為例描述Spark提交到混部K8s集群的流程并達(dá)到與傳統(tǒng)客戶端提交任務(wù)幾乎無差異的平滑切換。目前vivo的離線任務(wù)都是通過大數(shù)據(jù)平臺(tái)進(jìn)行提交和調(diào)度的,平臺(tái)會(huì)把主要的提交流程進(jìn)行封裝形成簡(jiǎn)單操作的功能,例如在平臺(tái)上提交SparkSql任務(wù)流程一般是編寫sql、提交任務(wù)、查看Driver日志或在跳轉(zhuǎn)到SparkUI、執(zhí)行完成后獲取結(jié)果以及更新任務(wù)狀態(tài)。

在平臺(tái)內(nèi)部,SparkSql任務(wù)使用傳統(tǒng)的spark-submit提交流程是:

  1. 用戶編寫好的sql上傳到提交節(jié)點(diǎn)生成一個(gè)sql文件;
  2. 在提交節(jié)點(diǎn)使用Spark客戶端執(zhí)行該sql文件啟動(dòng)SparkSql任務(wù);
  3. 任務(wù)啟動(dòng)后,通過不斷地tail操作查詢?nèi)罩巨D(zhuǎn)存到HBase方便在平臺(tái)頁面上查詢到Driver日志;
  4. 任務(wù)結(jié)束后,再查詢輸出結(jié)果轉(zhuǎn)存到HBase方便在平臺(tái)頁面上查詢到執(zhí)行結(jié)果;
  5. 根據(jù)提交sql任務(wù)命令的返回碼來更新任務(wù)狀態(tài)。

傳統(tǒng)Spark客戶端提交任務(wù)大部分只會(huì)涉及到提交節(jié)點(diǎn)的客戶端與平臺(tái)服務(wù)器之間的交互,而SparkSql任務(wù)提交到混部K8s集群,從上節(jié)的Spark容器化方案的原理可知最終目的是要將Spark任務(wù)的任務(wù)參數(shù)按一定的格式封裝好傳入Spark Operator控制器來創(chuàng)建相關(guān)的容器,平臺(tái)需要通過會(huì)調(diào)用容器團(tuán)隊(duì)提供的封裝好K8sApi的統(tǒng)一接入層來創(chuàng)建Spark容器。

圖片

在平臺(tái)內(nèi)部,SparkSql任務(wù)提交到混部K8s集群的完整流程為:

  1. 用戶編寫好的sql上傳到HDFS生成一個(gè)遠(yuǎn)程可訪問的HDFS文件;
  2. SparkSql任務(wù)參數(shù)封裝好傳入容器接入層的createSpark接口來調(diào)用Spark Operator控制器容器,再由Spark Operator控制器創(chuàng)建Driver Pod,最后由Driver Pod根據(jù)Spark任務(wù)需要?jiǎng)?chuàng)建多個(gè)Executor Pod,這些Driver、Executor的Pod相當(dāng)于Driver和Executor的角色,共同配合執(zhí)行Spark作業(yè);
  3. 任務(wù)啟動(dòng)后,通過容器接入層的getDriverLog接口周期性地查詢Driver日志,實(shí)質(zhì)上是查詢Driver容器的日志,查詢到的Driver日志會(huì)轉(zhuǎn)存到HBase方便在平臺(tái)頁面上查詢;
  4. 任務(wù)結(jié)束后,一方面通過Spark啟動(dòng)腳本中的日志上傳命令,把Driver和Executor的日志上傳HDFS,可以在改造后的Spark HistoryServer直接查看,另一方面執(zhí)行結(jié)果也會(huì)先輸出到HDFS,再從HDFS轉(zhuǎn)存到HBase方便在平臺(tái)頁面上查詢到執(zhí)行結(jié)果;
  5.  通過輪詢接入層的getSpark接口根據(jù)返回的狀態(tài)碼來更新任務(wù)狀態(tài),在任務(wù)結(jié)束后,此時(shí)Driver Pod不會(huì)主動(dòng)退出,首先將任務(wù)狀態(tài)更新為成功,在日志和結(jié)果都存儲(chǔ)完成后,再調(diào)用deleteSpark接口主動(dòng)地殺死Driver Pod釋放資源,完成整個(gè)Spark任務(wù)流程。

可以看出SparkSql任務(wù)提交到混部K8s的執(zhí)行主體是容器,因此需要增加容器接入層來管理Spark相關(guān)的容器,同時(shí)容器的使用更傾向于存算分離的效果,因此需要使用HDFS作為遠(yuǎn)程文件中轉(zhuǎn)。

大數(shù)據(jù)平臺(tái)上傳統(tǒng)使用spark-submit和onK8s使用spark-operator的SparkSql任務(wù)執(zhí)行流程對(duì)比如下:

圖片

3.2 混部任務(wù)的資源參數(shù)調(diào)整

Spark任務(wù)的Driver和Executor,在Yarn上執(zhí)行實(shí)質(zhì)是運(yùn)行在NodeManager節(jié)點(diǎn)上的,而在K8s上執(zhí)行實(shí)質(zhì)是運(yùn)行在對(duì)應(yīng)的Pod中的,由于Spark on K8s的提交方式和運(yùn)行環(huán)境都不同于on Yarn,任務(wù)的資源參數(shù)不能直接套用,需要做一些參數(shù)調(diào)整才能提交到K8s上。

1、資源參數(shù)提取和轉(zhuǎn)換

SparkSql任務(wù)在Yarn上可以靈活地調(diào)整sql中的配置來滿足不同特性的任務(wù),sql中的資源配置會(huì)覆蓋客戶端啟動(dòng)時(shí)的全局配置,因?yàn)镋xecutor是運(yùn)行在NodeManager節(jié)點(diǎn)上的,資源會(huì)相對(duì)充裕能滿足Executor的資源需求,與此不同的是Spark on K8s的Executor是運(yùn)行在Executor Pod中的,使用的資源會(huì)受到Pod資源規(guī)格大小的限制,而spark-operator的提交方式是要先獲取Executor全局資源規(guī)格并生成相應(yīng)資源規(guī)格大小的Executor Pod,所以在提交Spark任務(wù)到K8s前就要準(zhǔn)確地獲取任務(wù)真正生效的資源參數(shù)。在大數(shù)據(jù)平臺(tái)中資源參數(shù)會(huì)存在多中類型的參數(shù)中,參數(shù)的優(yōu)先級(jí)為:任務(wù)配置參數(shù) < 任務(wù)模板參數(shù) < sql中設(shè)置參數(shù) < HBO優(yōu)化參數(shù) < 平臺(tái)統(tǒng)一參數(shù),按此優(yōu)先級(jí)順序依次提取最終的資源參數(shù)并傳入容器接入層創(chuàng)建Spark作業(yè)。另外容器接入層對(duì)于Spark的arguments和sparkConf參數(shù)都是要求以字符數(shù)組的方式傳入,需要做好對(duì)原任務(wù)參數(shù)中的單引號(hào)、雙引號(hào)、反斜杠和回車等符號(hào)以及分段落的處理和轉(zhuǎn)換。

2、overheadMemory的計(jì)算

在Yarn上Executor是運(yùn)行在NodeManager節(jié)點(diǎn)上的,節(jié)點(diǎn)的資源一般都大于并能滿足container申請(qǐng)的資源,所以在Yarn上只需要關(guān)心container本身申請(qǐng)的資源即可,而在K8s上Executor運(yùn)行在對(duì)應(yīng)的Pod中,可以把Pod理解為只一臺(tái)獨(dú)立的節(jié)點(diǎn),除了要滿足container申請(qǐng)的資源量,還需要一些Pod容運(yùn)行時(shí)網(wǎng)絡(luò)、存儲(chǔ)等基礎(chǔ)設(shè)施的自身開銷資源,如果把Spark任務(wù)中Driver和Executor申請(qǐng)的資源直接設(shè)置為K8s中Driver Pod和Executor Pod的資源規(guī)格,有可能出現(xiàn)OOM情況,另外還要考慮非JVM內(nèi)存,Spark默認(rèn)會(huì)把申請(qǐng)的Executor內(nèi)存乘以一個(gè)系數(shù)或者至少預(yù)留384 MiB內(nèi)存作為額外的非JVM內(nèi)存緩沖區(qū),用于堆外內(nèi)存分配、非JVM任務(wù)以及各類系統(tǒng)進(jìn)程的使用,可以通過設(shè)置overheadMemory進(jìn)行覆蓋。因此K8s的Pod除了要滿足申請(qǐng)的Memory和運(yùn)行時(shí)需要的overheadMemory的資源,還會(huì)再添加100M資源用于Pod運(yùn)行的自身開銷。

pod的資源規(guī)格 = memory + pod overheadMemory

對(duì)于overheadMemory也需要先獲取到并加到Pod的資源規(guī)格,如果任務(wù)有配置就直接使用配置的overheadMemory,如果沒有配置值則按一定計(jì)算公式來計(jì)算得到。

有配置

pod overheadMemory = overheadMemory + 100M

無配置

pod overheadMemory = (max(384M,0.1*memory))向上取整到512MB的整數(shù)倍 + 100M

不過在實(shí)際應(yīng)用中發(fā)現(xiàn)對(duì)于個(gè)別任務(wù),即使K8s上配置的overheadMemory比在Yarn的配置多100M,完全一樣的任務(wù)在K8s上則有較多的Executor OOM情況,而在Yarn上卻完全沒有,目前排查到的現(xiàn)象是有JVM堆外的內(nèi)存無法回收,如果任務(wù)需要較多的對(duì)外內(nèi)存,堆外內(nèi)存一直增長(zhǎng)最終導(dǎo)致OOM,但哪些內(nèi)存無法回收的還未排查到。目前對(duì)于這些OOM過多且實(shí)際影響到運(yùn)行效率的任務(wù),在原overheadMemory基礎(chǔ)上再增加512M后就沒有OOM情況了,同時(shí)也有采用了大數(shù)據(jù)平臺(tái)的HBO能力自動(dòng)調(diào)整內(nèi)存參數(shù)來事后規(guī)避這個(gè)問題。

3、CPU超分配置

Spark任務(wù)申請(qǐng)的CPU使用一般不會(huì)使用完,事實(shí)上Executor Pod的CPU利用率也并不是很高,比如Executor申請(qǐng)1個(gè)核,通常只能利用0.6個(gè)核,存在CPU浪費(fèi)的現(xiàn)象。Executor Pod的資源規(guī)格是創(chuàng)建的時(shí)候分配的,利用容器的能力,可以采取CPU超分的方式提高CPU的利用率,例如Executor申請(qǐng)1核,實(shí)際用0.6核,如果Pod分配1核,那利用率就只有60%,但如果Pod只分配0.8核,那利用率就有75%了,所以超分的策略就是申請(qǐng)了1核只給0.8核,但還是要按1核的申請(qǐng)量來運(yùn)行任務(wù)。目前平臺(tái)使用的是靜態(tài)的固定比例超分設(shè)置為0.8,實(shí)施超分配置策略后Pod的實(shí)際CPU利用率打到80%以上。

圖片

3.3 混部任務(wù)的篩選提交

經(jīng)過上面的任務(wù)提交方式的改造和任務(wù)資源參數(shù)的調(diào)整,原SparkSql和SparkJar任務(wù)就可以平滑切換提交到混部K8s上執(zhí)行了,但在大規(guī)模切換之前平臺(tái)還做了比較長(zhǎng)期的雙跑驗(yàn)證工作,在執(zhí)行成功率、數(shù)據(jù)一致性和執(zhí)行時(shí)效等方案都進(jìn)行了雙跑比較,雙跑通過的任務(wù)才能切換到K8s上執(zhí)行。除了雙跑通過,前期還設(shè)置了其他的篩選條件如下。

圖片

前期按這些條件篩選出可以提交到K8s的任務(wù),然后分批的進(jìn)行K8s任務(wù)的參數(shù)標(biāo)記,并把標(biāo)記的這批任務(wù)添加監(jiān)控進(jìn)行跟蹤。經(jīng)過雙跑驗(yàn)證、任務(wù)篩選、批量標(biāo)記、監(jiān)控跟蹤和問題解決這一整套SparkSql任務(wù)上量K8s的流程,K8s上的任務(wù)運(yùn)行逐步穩(wěn)定,K8s的兼容問題也基本解決,因此目前取消了雙跑通過的這一條件,主要保留了任務(wù)重要性、運(yùn)行時(shí)長(zhǎng)和重試次數(shù)這幾個(gè)篩選指標(biāo)。隨著SparkSql任務(wù)上量和穩(wěn)定,提交到K8s的任務(wù)類型也增加了SparkJar任務(wù),SparkJar任務(wù)無法進(jìn)行雙跑驗(yàn)證,所以在各種K8s兼容問題解決后再推進(jìn)會(huì)更加穩(wěn)妥。

目前大數(shù)據(jù)平臺(tái)會(huì)定期篩選和標(biāo)記一批SparkSql和SparkJar任務(wù)允許提交到混部K8s,用戶也可以自行開啟,在任務(wù)配置頁面只顯示已開啟混部,則該任務(wù)就有機(jī)會(huì)被提交到混部K8s上執(zhí)行。當(dāng)然,用戶也可以手動(dòng)關(guān)閉這一開關(guān),并且手動(dòng)操作的優(yōu)先級(jí)最高,手動(dòng)關(guān)閉后平臺(tái)的自動(dòng)開啟功能將不再生效。

四、彈性調(diào)度系統(tǒng)

4.1 彈性調(diào)度功能矩陣

Spark任務(wù)開啟了混部也不是必定能提交到混部,最終能不能在混部集群上執(zhí)行,還要根據(jù)當(dāng)時(shí)混部集群的資源和運(yùn)行情況等來確定,為了更好地協(xié)調(diào)離線任務(wù)和混部集群的供需關(guān)系,大數(shù)據(jù)平臺(tái)構(gòu)建了離線任務(wù)混部彈性調(diào)度系統(tǒng)。彈性調(diào)度系統(tǒng)的設(shè)計(jì)目是混部集群有資源了就調(diào)度離線任務(wù),但在生產(chǎn)環(huán)境中不管是混部集群還是離線任務(wù)都會(huì)各自的問題需要解決和優(yōu)化的需求,彈性調(diào)度系統(tǒng)也逐步演變成了全面管理離線任務(wù)提交到混部以實(shí)現(xiàn)混部資源最大化利用的功能矩陣。

4.1.1 資源水位線調(diào)度

圖片

彈性調(diào)度的流程,任務(wù)按調(diào)度時(shí)間以任務(wù)流的形式過來,如果任務(wù)標(biāo)記了允許提交到混部,那就會(huì)先去查詢K8s的各個(gè)集群,如果某一個(gè)集群資源充足就直接提交到K8s,如果當(dāng)時(shí)沒有足夠資源就等待資源再判斷,這里分為有三類任務(wù),第一類是一直等K8s資源,永不超時(shí),只會(huì)提交到K8s;第二類是長(zhǎng)時(shí)間等待,超時(shí)時(shí)間在1到5分鐘,可以等久一點(diǎn);第三類是短時(shí)等待,超時(shí)時(shí)間為30-60秒,稍微等一下,如果K8s沒有資源就回到Y(jié)arn上執(zhí)行,目前平臺(tái)標(biāo)記的任務(wù)大部分任務(wù)都是第三類短時(shí)等待。

混部集群提供給離線任務(wù)的資源是呈潮汐波動(dòng)的,使用百分比的水位線方式才能更好地貼合資源的波動(dòng)情況?;觳考禾峁┑馁Y源是指CPU和內(nèi)存,但離線任務(wù)一般不能百分之百地獲取到這部分資源,需要設(shè)置一個(gè)折算比例也就是水位線來計(jì)算出離線任務(wù)能使用的真正資源是多少,水位線的設(shè)置需要考慮幾個(gè)因素

  1. 混部集群的碎片化率,混部集群中的機(jī)器規(guī)格和正在運(yùn)行的業(yè)務(wù)占用量都是不確定的,但一般大規(guī)格的機(jī)器多的集群碎片化率較低,所以小規(guī)格的機(jī)器多的集群的水位線要設(shè)置低一點(diǎn)。
  2. 資源動(dòng)態(tài)分配容納率,對(duì)于開啟了動(dòng)態(tài)分配的Spark任務(wù),無法提前知道任務(wù)所需的資源,需要留有一部分資源用于動(dòng)態(tài)分配的消耗,如果同樣的水位線資源規(guī)模大的混部集群容納率會(huì)高,所以資源規(guī)模小的集群的水位線要設(shè)置低一點(diǎn)。
  3. 資源配比的均衡性,不同的集群或者同一集群的不同時(shí)間段的CPU和內(nèi)存配比可能會(huì)存在很大的差異,例如Spark任務(wù)的CPU和內(nèi)存的平均比例是1核6G,即1:6,如果有CPU和內(nèi)存比為1:2的,內(nèi)存會(huì)被用完而CPU有剩余,此時(shí)為了內(nèi)存留有部分余量,水位線要設(shè)置低一點(diǎn)。

混部資源可用量 = 混部資源提供量 * 資源水位線

資源水位線有CPU水位線和內(nèi)存水位線,設(shè)計(jì)時(shí)以CPU或內(nèi)存中的最低水位線為準(zhǔn),哪個(gè)資源先分配完就停止提交任務(wù),不過在實(shí)際生產(chǎn)中大部分混部集群都是受內(nèi)存限制較多,個(gè)別時(shí)段CPU比內(nèi)存多但通過其他的限制手段即使CPU滿載對(duì)任務(wù)影響不大,因此目前只開啟了內(nèi)存資源水位線。以上提到的3點(diǎn)可以當(dāng)成集群的固有消耗需要保留有一定的余量,為了直觀地控制混部資源使用率和引入優(yōu)先策略,計(jì)算方式調(diào)整為:

混部資源可用量 = 混部資源提供量 * (1-余量水位線) * 優(yōu)先水位線

余量水位線根據(jù)各個(gè)集群來調(diào)整,一般為0.05,優(yōu)先水位線的范圍可以在0-1之間。優(yōu)先水位線的作用是對(duì)于一些符合優(yōu)先條件的任務(wù)可以優(yōu)先提交,但是任務(wù)調(diào)度是一有任務(wù)就要調(diào)度的流式調(diào)度,不能夠先集中再挑選優(yōu)先任務(wù)而是先到先得,所以要為優(yōu)先任務(wù)預(yù)留一部分資源,例如優(yōu)先水位線為0.8,混部資源使用到0.8以下的時(shí)候任何任務(wù)都可以調(diào)度上來,但使用量超過了0.8,那只有優(yōu)先任務(wù)能調(diào)上來,也就是為優(yōu)先任務(wù)預(yù)留了0.2的資源,當(dāng)然即使資源使用量達(dá)到了1,由于余量水位線的存在,實(shí)際的使用量為0.95,混部集群仍有資源維持周轉(zhuǎn)。優(yōu)先水位線是最常用的調(diào)整參數(shù),它實(shí)質(zhì)就是控制混部任務(wù)提交量,不僅能調(diào)整混部資源的使用量,還在灰度測(cè)試、壓力測(cè)試和問題排查等事項(xiàng)起到了靈活調(diào)節(jié)的作用。

4.1.2 其他調(diào)度能力

1.多集群管理:混部集群通常會(huì)有多個(gè),vivo目前就有多個(gè)生產(chǎn)環(huán)境的混部集群,各混部集群由于建設(shè)周期、機(jī)器規(guī)格和業(yè)務(wù)接入的不同,混部資源的規(guī)模和變化趨勢(shì)都會(huì)呈現(xiàn)比較大的差異,因此每個(gè)集群的調(diào)度策略配置都需要做到能獨(dú)立調(diào)整來適應(yīng)各自的資源特點(diǎn)。

2.分時(shí)段控制:每個(gè)混部集群上的在線業(yè)務(wù)一般是潮汐波動(dòng)的,給到離線任務(wù)的資源也是潮汐波動(dòng)的,因此每個(gè)集群需要做到在每天不同時(shí)段可以調(diào)整不同的調(diào)度策略,尤其在波峰波谷差異較大的時(shí)間段各自調(diào)整配置的差異會(huì)更大。

3.分散namespace:Spark任務(wù)的Driver Pod和Executor Pod都會(huì)放在一個(gè)namespace中管理,如果所有任務(wù)都由一個(gè)namespace管理,那需要管理的pod數(shù)量會(huì)達(dá)到數(shù)十萬的級(jí)別,會(huì)對(duì)K8s集群的性能和穩(wěn)定性產(chǎn)生影響。因此需要將Spark任務(wù)平均分配到多個(gè)namespace,采用的方案是輪詢填充,任務(wù)優(yōu)先分配到多個(gè)namespace中任務(wù)最少namespace。

4.失敗回退Yarn:離線任務(wù)混部推進(jìn)的過程中還有會(huì)有Spark兼容問題、混部集群異常和平臺(tái)變更等問題導(dǎo)致的離線任務(wù)在混部K8s上運(yùn)行失敗,為了減少失敗對(duì)任務(wù)的影響,任務(wù)在K8s上首次執(zhí)行失敗后就會(huì)自動(dòng)回到Y(jié)arn重新執(zhí)行。

5.資源準(zhǔn)入粒度:各混部集群的機(jī)器規(guī)格和碎片率是不一樣的,如executorMemory=2G這樣較小粒度的Spark任務(wù)即使碎片率較高的混部集群可以填充,而對(duì)于executorMemory=16G這樣較大粒度的Spark任務(wù),機(jī)器規(guī)格大的集群才更容易獲取到資源,因此不同混部集群可以設(shè)置不同的準(zhǔn)入粒度,小規(guī)格和碎片率高的集群準(zhǔn)入粒度可以設(shè)置小一些。

6.任務(wù)偏好配置:對(duì)于一些灰度任務(wù)和特殊要求的任務(wù),例如只有在0到8點(diǎn)才允許提交到混部、只提交到某幾個(gè)指定的混部集群等調(diào)度要求,需要支持任務(wù)偏好配置,在任務(wù)參數(shù)中調(diào)整混部控制參數(shù)實(shí)現(xiàn)相應(yīng)的調(diào)度需求。

4.2 彈性調(diào)度策略優(yōu)化

彈性調(diào)度的核心是通過資源水位線的調(diào)節(jié),有混部資源就調(diào)度離線任務(wù),但實(shí)際生產(chǎn)中還要考慮混部集群的運(yùn)行情況,是否能穩(wěn)定地接收和消化離線任務(wù),同時(shí)在存在多個(gè)差異較大的集群時(shí)提交到哪個(gè)集群最優(yōu)。

4.2.1 任務(wù)調(diào)度穩(wěn)定優(yōu)化

大數(shù)據(jù)平臺(tái)的離線任務(wù)提交高峰在凌晨時(shí)段而且調(diào)度時(shí)間集中在整點(diǎn)半點(diǎn),還有5分和10分這樣的整分,例如03:00調(diào)度的任務(wù)達(dá)1000個(gè),但在03:01調(diào)度的任務(wù)只有10個(gè),過于集中地提交任務(wù)會(huì)導(dǎo)致混部集群Pending Pod數(shù)量急劇上升,這是因?yàn)闊o論是查詢集群資源還是Pending數(shù)的接口,更新數(shù)據(jù)都需要一定的周期時(shí)間,而且離線任務(wù)提交上去到獲取資源也受K8s的調(diào)度時(shí)間的影響,所以獲取集群運(yùn)行情況總會(huì)滯后于任務(wù)提交。例如03:00查詢集群是有資源的并且是健康的,由于任務(wù)開啟了動(dòng)態(tài)分配所以不能確定需要多少資源,此時(shí)集中提交了1000個(gè)任務(wù),這1000個(gè)任務(wù)首先會(huì)創(chuàng)建1000個(gè)Driver Pod,集群資源還是能滿足的并且優(yōu)先創(chuàng)建,假如每個(gè)Driver需要?jiǎng)?chuàng)建100個(gè)Executor,如果集群沒有這么多資源,那就會(huì)產(chǎn)生大量的Penging Pod,嚴(yán)重影響集群的性能和穩(wěn)定以及任務(wù)的執(zhí)行效率,因此需要對(duì)彈性調(diào)度的穩(wěn)定性進(jìn)行優(yōu)化。

短時(shí)提交限制:避免集中提交任務(wù)的直接方案就是根據(jù)各混部集群的資源規(guī)模設(shè)置短時(shí)提交的任務(wù)數(shù)量限制,例如1分鐘內(nèi)只能提交100個(gè)任務(wù),集群短時(shí)間內(nèi)Pending Pod數(shù)量會(huì)增加但仍在可以承受范圍內(nèi),集群和任務(wù)都會(huì)穩(wěn)定運(yùn)行。短時(shí)提交限制相當(dāng)于攔截并舍棄了部分某個(gè)時(shí)間點(diǎn)集中提交的任務(wù),這里相當(dāng)于舍棄了900個(gè)任務(wù),那么提交的總?cè)蝿?wù)量就減少了。

延遲打散提交:為解決短時(shí)提交限制導(dǎo)致舍棄部分任務(wù)的問題,增加了短時(shí)延遲打散提交,例如03:00提交的1000個(gè)任務(wù),隨機(jī)打散到03:00到03:03的3分鐘內(nèi),即使有短時(shí)提交限制,這3分鐘內(nèi)也可以提交300個(gè)任務(wù)。理論上將集中提交的任務(wù)延遲更久,能提交到混部的任務(wù)會(huì)更多,但是增加延遲時(shí)長(zhǎng)就等于增加任務(wù)的執(zhí)行時(shí)長(zhǎng),會(huì)影響到業(yè)務(wù)數(shù)據(jù)產(chǎn)出的及時(shí)性,因此延遲打散提交策略只能是短時(shí)的,進(jìn)一步的優(yōu)化是執(zhí)行時(shí)長(zhǎng)更久的任務(wù)延遲更久一點(diǎn),但根本解決方案還是用戶能將調(diào)度時(shí)間盡量打散。

集群反饋限制:短時(shí)提交限制和延遲打散提交都屬于靜態(tài)限制,需要人為地根據(jù)各個(gè)混部集群的情況去判斷和設(shè)置限制值,因此需要做到動(dòng)態(tài)限制,就需要獲取集群的運(yùn)行情況并根據(jù)運(yùn)行情況進(jìn)行限制。事實(shí)上K8s的調(diào)度性能相比于Yarn還是有差距的,從提交的Spark任務(wù)到獲取到資源運(yùn)行Pod有一定的滯后時(shí)間差,這段時(shí)間查詢內(nèi)還是有剩余資源,但如果還繼續(xù)提交新任務(wù)就會(huì)產(chǎn)生更多Pending Pod,因此需要做集群運(yùn)行情況的反饋控制,例如查詢Pending Pod數(shù)、等待的SparkApp數(shù),當(dāng)數(shù)量達(dá)到一定數(shù)量就不再提交新任務(wù)。

集群反饋限制雖然是動(dòng)態(tài)的能根據(jù)混部集群情況進(jìn)行反饋調(diào)節(jié),但是查詢集群狀態(tài)是滯后的,這種滯后的控制就容易被集中提交給打垮,所以要加上短時(shí)提交限制來上一道保險(xiǎn),為緩解短時(shí)提交限制造成的任務(wù)損失,就引入了延遲打散提交,而在延時(shí)打散的過程中集群能逐步消化任務(wù),查詢集群狀態(tài)逐步接近真實(shí)情況,這時(shí)又可以交給集群反饋限制來動(dòng)態(tài)調(diào)節(jié),逐步從突增恢復(fù)到穩(wěn)定,三個(gè)調(diào)度穩(wěn)定優(yōu)化策略相輔相成。

4.2.2 集群分配均勻優(yōu)化

離線任務(wù)會(huì)調(diào)度到多個(gè)混部集群,每個(gè)集群的資源總量和可用資源量,以及集群運(yùn)行狀況都不相同,為保證離線任務(wù)的運(yùn)行穩(wěn)定和執(zhí)行效率,需要在多個(gè)混部集群中選擇一個(gè)最合適的集群。各個(gè)集群會(huì)按一定的規(guī)則進(jìn)行排序,離線任務(wù)會(huì)按這個(gè)排序依次輪詢各個(gè)集群,只要集群剩余資源滿足且沒有被短時(shí)提交限制、集群反饋限制等拒絕,離線任務(wù)就提交到該集群。集群排序的演化順序如下:

①初始方案

排隊(duì)隊(duì)列+輪詢

剩余資源量多的優(yōu)先

圖片

優(yōu)點(diǎn)

離線任務(wù)優(yōu)先提交到資源最多的集群,保證離線任務(wù)運(yùn)行穩(wěn)定

缺點(diǎn)

對(duì)于小集群剩余資源量很小一直分配不到任務(wù)容易“餓死”(事實(shí)上有的小集群全部資源量都達(dá)不到一個(gè)大集群的20%)

② 優(yōu)化方案

隨機(jī)隊(duì)列+排序隊(duì)列+輪詢

將資源使用量超過一定比例的集群放到排序隊(duì)列,剩余的集群放到隨機(jī)隊(duì)列

圖片

優(yōu)點(diǎn)

離線任務(wù)優(yōu)先提交到資源較多的集群,即保證任務(wù)的運(yùn)行穩(wěn)定,隨機(jī)的方式也能均勻“喂飽”每個(gè)集群

缺點(diǎn)

隨機(jī)分配在大任務(wù)量時(shí)相當(dāng)于是平均分配,每個(gè)集群都會(huì)調(diào)度差不多的任務(wù)量,當(dāng)前情況會(huì)存在整點(diǎn)集中提交大量任務(wù),小集群接收和大集群同樣任務(wù)量會(huì)抗不住,影響任務(wù)執(zhí)行穩(wěn)定和效率,小集群容易“撐死”

③再優(yōu)化方案

加權(quán)隨機(jī)隊(duì)列+排序隊(duì)列+輪詢

按剩余資源進(jìn)行加權(quán)隨機(jī),剩余資源多的集群有更多概率分配到任務(wù)

圖片

優(yōu)點(diǎn)

離線任務(wù)優(yōu)先提交到資源較多的集群,“大集群多吃,小集群少吃”,每個(gè)集群都能填充同時(shí)保證任務(wù)的運(yùn)行穩(wěn)定

④ 最終方案

優(yōu)先隊(duì)列(排序)+加權(quán)隨機(jī)隊(duì)列+排序隊(duì)列+輪詢

考慮優(yōu)先隊(duì)列,無視其他排序規(guī)則,優(yōu)先隊(duì)列里的集群將最優(yōu)先,在優(yōu)先隊(duì)列中的集群再按資源排序

圖片

優(yōu)點(diǎn)

繼承上一方案的優(yōu)點(diǎn),同時(shí)對(duì)于特定項(xiàng)目或機(jī)房的離線任務(wù),能優(yōu)先調(diào)度到某些特定的集群

目前只以內(nèi)存作為資源水位線的衡量標(biāo)準(zhǔn),這里的資源量指的是內(nèi)存量。最開始方案是按集群的剩余資源排序,內(nèi)存資源剩余多的集群優(yōu)先,缺點(diǎn)是小集群一直分配不到任務(wù)容易“餓死”,然后使用隨機(jī)的方式也能均勻“喂飽”每個(gè)集群,但小集群接收同樣任務(wù)量時(shí)容易“撐死”,于是隨機(jī)隊(duì)列按剩余資源進(jìn)行加權(quán)隨機(jī),剩余資源多的集群有更多概率分配到任務(wù),這樣離線任務(wù)優(yōu)先提交到資源較多的集群,“大集群多吃,小集群少吃”,每個(gè)集群都能填充同時(shí)保證任務(wù)的運(yùn)行穩(wěn)定,在此基礎(chǔ)上增加優(yōu)先隊(duì)列,無視其他排序規(guī)則,優(yōu)先隊(duì)列里的集群將最優(yōu)先,在優(yōu)先隊(duì)列中的集群再按資源排序,能優(yōu)先調(diào)度到某些特定的集群,形成最終集群選擇排序方案。

五、混部的效果與未來規(guī)劃

經(jīng)過以上的對(duì)Spark組件、K8s混部系統(tǒng)、大數(shù)據(jù)平臺(tái)以及彈性調(diào)度系統(tǒng)的改造和優(yōu)化,目前混部集群及提交混部的離線任務(wù)運(yùn)行持續(xù)穩(wěn)定,每天任務(wù)調(diào)度到混部的次數(shù)達(dá)10+萬次,在凌晨的高峰期通過混部能為離線任務(wù)額外增加數(shù)百TB內(nèi)存的計(jì)算資源,部分混部集群的CPU利用率提升至30%左右,整體收益也是可觀的。

雖然目前vivo的在離線混部達(dá)到了一定的規(guī)模,但未來要繼續(xù)提高混部的規(guī)模和收益,還有規(guī)劃一些改進(jìn)工作。

1、提高離線任務(wù)混部規(guī)模。

離線任務(wù)混部的節(jié)點(diǎn)是在線業(yè)務(wù)提供的,節(jié)點(diǎn)規(guī)模取決于在線業(yè)務(wù)峰值,峰值越高那么在業(yè)務(wù)低峰期能提供給離線混部資源就越多,因此提高混部規(guī)模的重要因素是提交更多的離線任務(wù)。然而目前采用的Spark Operator方案能提交的離線任務(wù)只有標(biāo)準(zhǔn)的SparkSql和SparkJar任務(wù),而對(duì)于非標(biāo)準(zhǔn)的任務(wù)如腳本任務(wù),腳本中除了調(diào)用spark-submit提交Spark作業(yè)還有額外的處理邏輯,這類任務(wù)還不能直接以Spark Operator的方式提交。事實(shí)上Spark作業(yè)更多是來自腳本任務(wù)的非標(biāo)準(zhǔn)任務(wù),如果要繼續(xù)增加離線任務(wù)的量,就必須把非標(biāo)準(zhǔn)任務(wù)也提交到混部,因此后續(xù)是選擇改造spark-submit客戶端支持Spark Operator,或是選擇使用Yarn on K8s,還需要綜合評(píng)估。

2、提高離線任務(wù)混部收益。

目前混部節(jié)點(diǎn)CPU的平均利用率達(dá)到30%,但仍有提升空間。從離線任務(wù)的角度來看,一方面是要增加錯(cuò)峰互補(bǔ)的時(shí)間段,例如離線任務(wù)的高峰期是02:00到08:00,在線業(yè)務(wù)的高峰期是06:00到23:00,在06:00后在線業(yè)務(wù)逐步上量開始回收資源,所以離線任務(wù)能顯著提高混部集群CPU利用率的黃金時(shí)間是有02:00到06:00這4個(gè)小時(shí),因此如果能把離線任務(wù)高峰期提前到00:00到06:00,混部提效的黃金時(shí)間就能達(dá)到6小時(shí)。所以需要推動(dòng)離線任務(wù)高峰期的前移,對(duì)于有依賴鏈路的任務(wù),盡量減少調(diào)度時(shí)間的間隔,上游任務(wù)完成后能盡快調(diào)起下游任務(wù),而對(duì)于沒有依賴的任務(wù),可以盡量提前調(diào)度時(shí)間,不過這兩種調(diào)整都需要推動(dòng)業(yè)務(wù)方來調(diào)整,平臺(tái)也可以給予一定的計(jì)算成本優(yōu)惠作為激勵(lì)。另一方面是要提高混部資源的填充率,Spark任務(wù)需要?jiǎng)?chuàng)建大量的Executor Pod,目前混部集群的調(diào)度器為了保證調(diào)度效率就沒有開啟預(yù)選、優(yōu)先策略,事實(shí)上Spark的資源粒度比較小更適合填充資源碎片,所以在不影響K8s調(diào)度效率的情況下優(yōu)化資源調(diào)配策略,把合適的資源粒度的Pod分配到合適的混部節(jié)點(diǎn),也是提高混部收益的方向。

責(zé)任編輯:龐桂玉 來源: vivo互聯(lián)網(wǎng)技術(shù)
相關(guān)推薦

2024-02-29 09:17:43

數(shù)據(jù)中心

2022-07-18 18:48:32

Kubernetes云原生

2023-09-06 08:12:04

k8s云原生

2022-05-31 11:34:24

BDOS智領(lǐng)云DPaSS

2022-10-10 12:54:00

Flink運(yùn)維

2023-11-06 01:17:25

主機(jī)容器選項(xiàng)

2024-02-01 09:48:17

2022-04-22 13:32:01

K8s容器引擎架構(gòu)

2023-11-06 07:16:22

WasmK8s模塊

2024-03-01 19:59:17

2022-08-21 07:25:09

Flink云原生K8S

2023-09-08 08:09:12

k8sservice服務(wù)

2023-02-27 07:40:00

2020-05-25 13:47:49

K8S,Jenkins

2022-06-10 09:39:48

云原生節(jié)點(diǎn)水位線

2023-11-15 13:44:00

k8s-域名日志

2023-03-06 07:19:50

2023-11-27 13:54:00

kubernetes高可用

2023-09-15 08:00:20

Ingress網(wǎng)關(guān)Istio

2024-05-20 15:39:00

Karmada混合云多云
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)