Kubernetes部署讓Spark更靈活
作者 | 陽(yáng)沁珂
Spark 是一個(gè)開(kāi)源的數(shù)據(jù)處理框架,能快速處理大量數(shù)據(jù)的轉(zhuǎn)換。其高性能來(lái)自Spark的分布式框架,通常一個(gè)任務(wù)會(huì)被平均分配,跨機(jī)器集群工作。但Spark本身并不管理這些計(jì)算機(jī),他需要一個(gè)集群的管理器來(lái)管理集群。Spark定義了需要執(zhí)行的任務(wù),而管理器決定了任務(wù)將如何被分配被執(zhí)行,由此可見(jiàn)其重要性。這個(gè)管理器需要負(fù)責(zé)任務(wù)的接收、資源的調(diào)度和分配、任務(wù)的啟動(dòng)、TaskTrack監(jiān)控等。
傳統(tǒng)上,我們會(huì)選擇Hadoop YARN來(lái)作為資源調(diào)度管理器,并且使用spark-submit提交任務(wù)。但隨著云計(jì)算的推廣與容器的流行,因其需要依賴于HDFS的本地環(huán)境,YARN的部署方式顯得捉襟見(jiàn)肘。在技術(shù)的遞進(jìn)下,從Spark3.3.1開(kāi)始正式推出了Kubernetes的資源管理方式,其設(shè)計(jì)框架與云計(jì)算緊密結(jié)合,將Spark應(yīng)用從本地HDFS集群中解耦合,賦予其更多的靈活性。
YARN Spark的傳統(tǒng)部署方式
YARN是一種資源管理系統(tǒng),其建筑于Hadoop之上,用于管理協(xié)調(diào)多個(gè)機(jī)器之間的任務(wù)提交執(zhí)行和監(jiān)控。
Spark部署在YARN集群上,需要開(kāi)發(fā)人員在安裝有Hadoop的每個(gè)機(jī)器配置上JAVA,Scala,YARN和Spark,并且不同機(jī)器之間可以免密登錄,還需要修改多個(gè)配置文件來(lái)明確master和slave節(jié)點(diǎn)。(詳細(xì)配置過(guò)程請(qǐng)參考running Spark on YARN)在任務(wù)提交之后,會(huì)首先向資源管理Resource manager申請(qǐng)資源,并且決定driver和executor node的分布。在我們配置集群時(shí),就要考慮到將來(lái)的任務(wù)需要的資源量,如果工作負(fù)載高而資源不足,將顯著拖慢集群性能。
將Spark提交給YARN執(zhí)行有兩種模式,yarn-client和yarn-cluster。yarn-client是將driver執(zhí)行在提交任務(wù)的客戶端上,而yarn-cluster是將driver執(zhí)行在集群的某臺(tái)機(jī)器上。采用client 模式可以方便開(kāi)發(fā)者查看driver的log,但如果driver和cluster不在同一個(gè)集群中,需要考慮通信帶寬的限制。
提交的方式通常我們采用spark-submit的方法,在參數(shù)中指明提交到Y(jié)ARN中:
YARN Spark的困境
在實(shí)際的生產(chǎn)中使用傳統(tǒng)的YARN的部署方式,我們可能會(huì)遇見(jiàn)以下的場(chǎng)景:
在初期搭建一個(gè)YARN on Hadoop是需要大量工作的,并且需要有相關(guān)經(jīng)驗(yàn)的工程師來(lái)進(jìn)行調(diào)整,因?yàn)榇蟛糠值脑O(shè)定需要通過(guò)conf去修改,并且需要在各個(gè)機(jī)器之間配置免密登錄。在使用時(shí),不僅僅是初期搭建,在運(yùn)營(yíng)維護(hù)上也有額外的成本。使用過(guò)一定時(shí)間的YARN on Hadoop需要升級(jí)jdk或者Spark版本時(shí),很容易因?yàn)閖dk不兼容造成整個(gè)生產(chǎn)環(huán)境宕機(jī)。這就需要配備專業(yè)的人員來(lái)維護(hù)各個(gè)機(jī)器的環(huán)境。
YARN在做第一次配置的時(shí)候就需要預(yù)估好生產(chǎn)所需的資源。假設(shè)我們配備了10臺(tái)機(jī)器的集群來(lái)處理線上消費(fèi)訂單,但雙十一的活動(dòng)使得訂單激增,為了保證能高性能完成任務(wù),我們臨時(shí)決定再增加五臺(tái)機(jī)器,提高并行度。經(jīng)過(guò)一整夜的配置調(diào)試,終于擴(kuò)大了集群,能及時(shí)處理線上的訂單。但當(dāng)雙十一過(guò)去后,訂單量銳減,YARN集群的15臺(tái)機(jī)器,總是有一半以上是空置的。但已經(jīng)購(gòu)買和配置好的資源,變成了固定資產(chǎn),很難再減少到10臺(tái)機(jī)器。
如果你的項(xiàng)目也遇見(jiàn)了上述的情況,了解下面這種新的Spark部署方法可能可以幫助你走出困境。
Spark on Kubernetes的部署
云計(jì)算在近幾年飛速發(fā)展,云已經(jīng)變成了許多公司的首選。為了更好地滿足Spark應(yīng)用的云遷移需求,Spark on Kubernetes的部署方法于 Spark 2.3 版本引入開(kāi)始,到 Spark 3.1 社區(qū)標(biāo)記 GA,基本上已經(jīng)具備了在生產(chǎn)環(huán)境大規(guī)模使用的條件。
Kubernetes(也稱 k8s 或 “kube”)是一個(gè)開(kāi)源的容器編排平臺(tái),可以自動(dòng)完成在部署、管理和擴(kuò)展容器化應(yīng)用過(guò)程中涉及的許多手動(dòng)操作。主流的云平臺(tái)都提供Kubernetes的應(yīng)用,如Amazon Elastic Kubernetes Service (Amazon EKS) , Azure Kubernetes Service (AKS) 等。
深度解析Spark on Kubernetes的部署架構(gòu)是由Kubernetes的應(yīng)用接受spark-submit的命令,可以查看到Kubernetes啟動(dòng)一個(gè)driver和多個(gè)executor的pod,當(dāng)任務(wù)完成之后,container的狀態(tài)會(huì)轉(zhuǎn)為complete。下面我們會(huì)介紹幾種在這種部署下的任務(wù)提交方法。
Submit提交
使用spark-submit命令可以直接向Kubernetes集群提交Spark應(yīng)用程序。其提交的命令與Spark on YARN的提交方式幾乎一致,唯一的區(qū)別是需要修改master的鏈接到Kubernetes的集群。
Operator提交
除了直接向 Kubernetes Scheduler 提交作業(yè)的方式,還可以通過(guò) Spark Operator 的方式來(lái)提交,Operator 在 Kubernetes 中是一個(gè)里程碑似的產(chǎn)物。Operator的安裝可以使用helm快速部署(quick-start-guide)。他將Spark的任務(wù)提交與傳統(tǒng)Kubernetes的yaml apply方法相結(jié)合,將許多的Spark調(diào)度參數(shù)管理轉(zhuǎn)為方便管理文檔模式。如下圖的yaml是一個(gè)向Kubernetes部署應(yīng)用的例子。可以看見(jiàn)在這個(gè)部署中,部署了一個(gè)叫spark-pi的應(yīng)用,使用gcr.io/spark/spark:v3.1.1的鏡像,如果需要其他版本的Spark,切換基礎(chǔ)鏡像即可。應(yīng)用的部署是cluster的模式,會(huì)啟動(dòng)一個(gè)driver和1個(gè)executor來(lái)完成jar文件中的SparkPi應(yīng)用。此外,ServiceAccount可以和Kubernetes的secret管理相結(jié)合,更好地管理應(yīng)用的安全密鑰。
Airflow的提交
一般的應(yīng)用都需要與Airflow結(jié)合起來(lái)做到執(zhí)行管理,傳統(tǒng)的Spark on YARN,都會(huì)選擇SSHOperator或者SparkSubmitOperator,使用spark-submit的方式提交通過(guò)Airflow提交任務(wù)。在Spark與Kubernetes結(jié)合之后,Airflow也開(kāi)發(fā)了新的組件支持:使用yaml提交任務(wù)到Kubernetes的SparkKubernetesOperator和用于監(jiān)聽(tīng)的SparkKubernetesSensor。對(duì)于Spark所需的參數(shù)化管理,我們可以使用jinja的語(yǔ)法定義好yaml的template,在實(shí)時(shí)執(zhí)行的時(shí)候傳入?yún)?shù)生成最終的執(zhí)行yaml。其dag代碼如下:
在Airflow的UI上可以看見(jiàn)dag有兩個(gè)operator,一個(gè)負(fù)責(zé)提交Spark應(yīng)用,一個(gè)負(fù)責(zé)監(jiān)聽(tīng)Spark應(yīng)用是否成功地收集log信息。
Kubernetes 與 YARN 對(duì)比
環(huán)境隔離
不同于YARN的機(jī)器只能擁有一個(gè)JAVA_HOME,Kubernetes是基于容器來(lái)進(jìn)行管理的,不同容器的環(huán)境是隔離的,相互不影響,環(huán)境的隔離顆粒度更細(xì)。當(dāng)需要進(jìn)行Spark版本升級(jí)時(shí),直接通過(guò)修改基礎(chǔ)鏡像的版本即可。并且在啟動(dòng)時(shí),不需要修改conf和配置免密登錄等額外的配置工作。
更易擴(kuò)展
使用Kubernetes,資源不再是固定離線的了,而是動(dòng)態(tài)啟動(dòng)的。executor是由pod來(lái)完成,當(dāng)運(yùn)算完成之后,會(huì)立即釋放pod占用的空間。特別是與云資源相結(jié)合,比如AWS的EKS(Elastic Kubernetes Service),可以做到極好的成本控制。當(dāng)計(jì)算峰值來(lái)臨時(shí),可以彈性增長(zhǎng),并且在峰值過(guò)后,立即降低釋放資源。
學(xué)習(xí)成本
不同于傳統(tǒng)的部署方式,Kubernetes是完全建立在pods上的,并且要完全發(fā)揮其靈活擴(kuò)展的特性需要與云計(jì)算相結(jié)合。這就注定了,使用Kubernetes部署的開(kāi)發(fā)者不僅僅需要了解Spark的基礎(chǔ)框架,還需要精通pods部署與基礎(chǔ)云知識(shí)。
數(shù)據(jù)湖
傳統(tǒng)的Spark集群,會(huì)將數(shù)據(jù)直接存儲(chǔ)在Hive或者HDFS中,實(shí)現(xiàn)本地化的數(shù)據(jù)湖。但是使用Kubernetes部署的Spark,是計(jì)算與存儲(chǔ)隔離的架構(gòu),啟動(dòng)的執(zhí)行pods是臨時(shí)的,并不能作為長(zhǎng)久的數(shù)據(jù)存儲(chǔ)。一般數(shù)據(jù)也將放在云系統(tǒng)如snowflake,s3數(shù)據(jù)湖中。
日志
和Spark on YARN的很大的區(qū)別是,Kubernetes的log是存在于不同的pod上的,其自帶的功能并不支持將所有l(wèi)og集合到一個(gè)web UI上查看。如有查看日志需要,開(kāi)發(fā)者需要kubectl logs命令指定查看一個(gè)pod的log,當(dāng)pod執(zhí)行完成被清理的時(shí)候log的信息也丟失了。使用Spark history web應(yīng)用,我們需要將pod內(nèi)存的log長(zhǎng)久化(比如存在aws S3bucket上),然后deploy一個(gè)Spark history server指向到我們所存儲(chǔ)的位置上。其部署過(guò)程需要改動(dòng)幾個(gè)config,參考:Spark history on k8s。
性能對(duì)比
因?yàn)镾park和Kubernetes都是主要負(fù)責(zé)計(jì)算資源和任務(wù)的調(diào)度,不涉及任何應(yīng)用框架上的差別,所以其性能本身的差別是微乎甚微的。由TPC-DS提供的基準(zhǔn)測(cè)試來(lái)看,兩者之間只有4.5%的差距,是幾乎可以忽略的。另外一方面,Spark on Kubernetes 一般選擇存算分離的架構(gòu),而 YARN 集群一般和 HDFS 耦合在一起,前者會(huì)在讀寫(xiě) HDFS 時(shí)喪失“數(shù)據(jù)本地性”,數(shù)據(jù)的讀寫(xiě)將受限于網(wǎng)絡(luò)的性能。但隨著網(wǎng)絡(luò)性能的發(fā)展,各種高效的傳輸和壓縮算法的出現(xiàn),這影響也幾乎可以忽略不計(jì)。
成本對(duì)比
我們之前有提及,Spark是離線資源,需要提前預(yù)估好需要的資源量,并且在應(yīng)急擴(kuò)展后很難將成本再降回來(lái),即使資源空置,成本依舊在那里。但Kubernetes的基礎(chǔ)是云,其部署完全可以實(shí)現(xiàn)動(dòng)態(tài)按需增長(zhǎng)的資源,可以說(shuō)不會(huì)存在需要為空閑未被使用的資源付費(fèi)的需求。這是Kubernetes部署方式的一大優(yōu)勢(shì),也是其深受用戶追捧的主要原因之一。
總結(jié)
自從 2018 年初隨著 2.3.0 版本發(fā)布以來(lái),Spark on Kubernetes 經(jīng)過(guò)長(zhǎng)期的發(fā)展和版本更新,在社區(qū)和用戶的打磨下已經(jīng)擁有成熟的特性。現(xiàn)在IT設(shè)備的成本逐年上漲,給許多企業(yè)帶來(lái)難題。Spark+Kubernetes+云的組合的靈活性和超高性價(jià)比,給用戶帶來(lái)了更多的想象空間。Kubernetes的容器式管理Spark應(yīng)用是很好的實(shí)踐,如果有云端或者混合部署的需求,建議采用Spark on Kubernetes的方式來(lái)統(tǒng)一管理,更好地實(shí)現(xiàn)與云計(jì)算的結(jié)合,并且靈活控制成本。但若大量數(shù)據(jù)仍是在本地存儲(chǔ),或者有其他Hadoop的應(yīng)用需求,Kubernetes并不能很好地滿足這些需求,還是建議維持YARN的部署方式。