注:本文參考文獻(xiàn)有書籍《Spark大數(shù)據(jù)處理:技術(shù)浸策、應(yīng)用與性能優(yōu)化》盆佣、RDD的Paper《Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing》局义。從三個(gè)部分來解讀Spark-core痊远,首先是Spark的架構(gòu),闡述了Spark基于彈性分布式數(shù)據(jù)集RDD這個(gè)計(jì)算模型的工作機(jī)制(計(jì)算流程):Application->Job->Stage->Task 的分解、分發(fā)和并行計(jì)算鳞滨;接下去從計(jì)算模型和工作機(jī)制兩個(gè)方面芬骄,分別解讀RDD的設(shè)計(jì)思想及其算子,以及劃分RDD有向無環(huán)圖為Stage和Task蹋半、并行計(jì)算的工作機(jī)制他巨。進(jìn)一步的原理分析和源碼研讀將在該系列的后續(xù)文章中撰寫。
Spark的架構(gòu)
Spark采用了分布式計(jì)算中的Master-Slave模型减江。Master作為整個(gè)集群的控制器染突,負(fù)責(zé)整個(gè)集群的正常運(yùn)行;Worker是計(jì)算節(jié)點(diǎn)辈灼,接受主節(jié)點(diǎn)命令以及進(jìn)行狀態(tài)匯報(bào)份企;Executor負(fù)責(zé)任務(wù)(Tast)的調(diào)度和執(zhí)行;Client作為用戶的客戶端負(fù)責(zé)提交應(yīng)用巡莹;Driver負(fù)責(zé)控制一個(gè)應(yīng)用的執(zhí)行司志。
Spark架構(gòu)圖:出自《Spark大數(shù)據(jù)處理》
Spark集群啟動(dòng)時(shí),需要從主節(jié)點(diǎn)和從節(jié)點(diǎn)分別啟動(dòng)Master進(jìn)程和Worker進(jìn)程降宅,對整個(gè)集群進(jìn)行控制骂远。在一個(gè)Spark應(yīng)用的執(zhí)行過程中,Driver是應(yīng)用的邏輯執(zhí)行起點(diǎn)腰根,運(yùn)行Application的main函數(shù)并創(chuàng)建SparkContext激才,DAGScheduler把對Job中的RDD有向無環(huán)圖根據(jù)依賴關(guān)系劃分為多個(gè)Stage,每一個(gè)Stage是一個(gè)TaskSet额嘿, TaskScheduler把Task分發(fā)給Worker中的Executor瘸恼;Worker啟動(dòng)Executor,Executor啟動(dòng)線程池用于執(zhí)行Task岩睁。
Spark執(zhí)行有向無環(huán)圖:出自《Spark大數(shù)據(jù)處理》
Spark的計(jì)算模型
RDD:彈性分布式數(shù)據(jù)集钞脂,是一種內(nèi)存抽象,可以理解為一個(gè)大數(shù)組捕儒,數(shù)組的元素是RDD的分區(qū)Partition冰啃,分布在集群上邓夕;在物理數(shù)據(jù)存儲(chǔ)上,RDD的每一個(gè)Partition對應(yīng)的就是一個(gè)數(shù)據(jù)塊Block阎毅,Block可以存儲(chǔ)在內(nèi)存中焚刚,當(dāng)內(nèi)存不夠時(shí)可以存儲(chǔ)在磁盤上。
RDD邏輯物理結(jié)構(gòu)
Hadoop將Mapreduce計(jì)算的結(jié)果寫入磁盤扇调,在機(jī)器學(xué)習(xí)矿咕、圖計(jì)算、PageRank等迭代計(jì)算下狼钮,重用中間結(jié)果導(dǎo)致的反復(fù)I/O耗時(shí)過長碳柱,成為了計(jì)算性能的瓶頸。為了提高迭代計(jì)算的性能和分布式并行計(jì)算下共享數(shù)據(jù)的容錯(cuò)性熬芜,伯克利的設(shè)計(jì)者依據(jù)兩個(gè)特性而設(shè)計(jì)了RDD:
1莲镣、數(shù)據(jù)集分區(qū)存儲(chǔ)在節(jié)點(diǎn)的內(nèi)存中,減少迭代過程(如機(jī)器學(xué)習(xí)算法)反復(fù)的I/O操作從而提高性能涎拉。
2瑞侮、數(shù)據(jù)集不可變,并記錄其轉(zhuǎn)換過程鼓拧,從而實(shí)現(xiàn)無共享數(shù)據(jù)讀寫同步問題半火、以及出錯(cuò)的可重算性。
Operations:算子
算子是RDD中定義的函數(shù)季俩,可以對RDD中的數(shù)據(jù)進(jìn)行轉(zhuǎn)換和操作钮糖。如下圖,Spark從外部空間(HDFS)讀取數(shù)據(jù)形成RDD_0酌住,Tranformation算子對數(shù)據(jù)進(jìn)行操作(如fliter)并轉(zhuǎn)化為新的RDD_1藐鹤、RDD_2,通過Action算子(如collect/count)觸發(fā)Spark提交作業(yè)赂韵。
如上的分析過程可以看出,Tranformation算子并不會(huì)觸發(fā)Spark提交作業(yè)挠蛉,直至Action算子才提交作業(yè)祭示,這是一個(gè)延遲計(jì)算的設(shè)計(jì)技巧,可以避免內(nèi)存過快被中間計(jì)算占滿谴古,從而提高內(nèi)存的利用率质涛。
Spark算子:出自《Spark大數(shù)據(jù)處理》
下圖是算子的列表,分三大類:Value數(shù)據(jù)類型的Tranformation算子掰担;Key-Value數(shù)據(jù)類型的Tranformation算子汇陆;Action算子。
RDD的算子:出自伯克利的RDD論文
Lineage Graph:血統(tǒng)關(guān)系圖
下圖的第一階段生成RDD的有向無環(huán)圖带饱,即是血統(tǒng)關(guān)系圖毡代,記錄了RDD的更新過程阅羹,當(dāng)這個(gè)RDD的部分分區(qū)數(shù)據(jù)丟失時(shí),它可以通過Lineage獲取足夠的信息來重新運(yùn)算和恢復(fù)丟失的數(shù)據(jù)分區(qū)教寂。DAGScheduler依據(jù)RDD的依賴關(guān)系將有向無環(huán)圖劃分為多個(gè)Stage捏鱼,一個(gè)Stage對應(yīng)著一系列的Task,由TashScheduler分發(fā)給Worker計(jì)算酪耕。
RDD運(yùn)行變化圖
Spark的工作機(jī)制
本模塊從六個(gè)方面导梆,介紹Spark的內(nèi)部運(yùn)行機(jī)制。
應(yīng)用執(zhí)行機(jī)制
Spark應(yīng)用(Application)是用戶提交的應(yīng)用程序迂烁,執(zhí)行模式有Local看尼、Standalone、YARN盟步、Mesos藏斩。根據(jù)Application的Driver Program(或者YARN的AppMaster)是否在集群中運(yùn)行,Spark應(yīng)用的運(yùn)行方式又可以分為Cluster模式和Client模式址芯。
Standalone模式
Driver運(yùn)行在客戶端
Driver運(yùn)行在客戶端:出自網(wǎng)絡(luò)
Driver運(yùn)行在Worker
Driver運(yùn)行在Worker:出自網(wǎng)絡(luò)
YARN模式
Spark on YARN架構(gòu):出自《Spark大數(shù)據(jù)處理》
調(diào)度與任務(wù)分配
從Spark整體上看灾茁,調(diào)度可以分為4個(gè)級別,Application調(diào)度 -> Job調(diào)度 -> Stage調(diào)度 -> Task調(diào)度谷炸。
Spark應(yīng)用轉(zhuǎn)換流程:出自《Spark大數(shù)據(jù)處理》
I/O機(jī)制
序列化
塊管理
通信機(jī)制
Spark在模塊間通信使用的是AKKA框架北专。AKKA基于Scala開發(fā),用于編寫Actor應(yīng)用旬陡。Actors是一些包含狀態(tài)和行為的對象拓颓。它們通過顯式傳遞消息來進(jìn)行通信,這些消息會(huì)被發(fā)送到它們的收信箱中(消息隊(duì)列)描孟。
容錯(cuò)機(jī)制
Lineage機(jī)制:記錄粗粒度的更新
Checkpoint機(jī)制:將RDD寫入Disk做檢查點(diǎn)驶睦。檢查點(diǎn)的本質(zhì)是作為Lineage做容錯(cuò)的輔助,lineage過長會(huì)造成容錯(cuò)成本過高匿醒。在計(jì)算的中間階段做檢查點(diǎn)容錯(cuò)场航,如果之后的節(jié)點(diǎn)出現(xiàn)問題而丟失分區(qū),從做檢查點(diǎn)的RDD開始重做Lineage廉羔,就可以減少開銷溉痢。
Shuffle機(jī)制
當(dāng)單進(jìn)程空間無法容納所有計(jì)算數(shù)據(jù)進(jìn)行計(jì)算時(shí),通過Shuffle將各個(gè)節(jié)點(diǎn)上相同的key拉取到某個(gè)節(jié)點(diǎn)上的一個(gè)task來進(jìn)行處理憋他,比如按照key進(jìn)行聚合或join等操作孩饼。此時(shí)如果某個(gè)key對應(yīng)的數(shù)據(jù)量特別大的話,就會(huì)發(fā)生數(shù)據(jù)傾斜竹挡。數(shù)據(jù)傾斜是Spark性能優(yōu)化的一個(gè)重大課題镀娶。
可能會(huì)觸發(fā)shuffle操作的算子 :distinct、groupByKey揪罕、reduceByKey梯码、aggregateByKey宝泵、join、cogroup忍些、repartition等鲁猩。
Shuffle分為兩個(gè)階段:Shuffle Write和Shuffle Fetch。如下圖: