from: http://www.linuxidc.com/Linux/2016-03/129506.htm
目前按照大數(shù)據(jù)處理類型來(lái)分大致可以分為:批量數(shù)據(jù)處理、交互式數(shù)據(jù)查詢、實(shí)時(shí)數(shù)據(jù)流處理,這三種數(shù)據(jù)處理方式對(duì)應(yīng)的業(yè)務(wù)場(chǎng)景也都不一樣;
關(guān)注大數(shù)據(jù)處理的應(yīng)該都知道Hadoop,而Hadoop的核心為HDFS與MapReduce,HDFS分布式文件系統(tǒng)在Hadop中是用來(lái)存儲(chǔ)數(shù)據(jù)的;MapReduce為Hadoop處理數(shù)據(jù)的核心,接觸過(guò)函數(shù)式編程的都知道函數(shù)式語(yǔ)言中也存在著Map、Reduce函數(shù)其實(shí)這兩者的思想是一致的;也正是因?yàn)镠adoop數(shù)據(jù)處理核心為MapReduce奠定了它注定不是適用場(chǎng)景廣泛的大數(shù)據(jù)框架;
可以這么說(shuō)Hadoop適用于Map、Reduce存在的任何場(chǎng)景,具體場(chǎng)景比如:WordCount、排序、PageRank、用戶行為分析、數(shù)據(jù)統(tǒng)計(jì)等,而這些場(chǎng)景都算是批量數(shù)據(jù)處理,而Hadoop并不適用于交互式數(shù)據(jù)查詢、實(shí)時(shí)數(shù)據(jù)流處理;
這時(shí)候就出現(xiàn)了各種數(shù)據(jù)處理模型下的專用框架如:Storm、Impala、GraphLab等;
1、Storm:針對(duì)實(shí)時(shí)數(shù)據(jù)流處理的分布式框架;
2、Impala:適用于交互式大數(shù)據(jù)查詢的分布式框架;
3、GraphLab:基于圖模型的機(jī)器學(xué)習(xí)框架;
1、MapReduce簡(jiǎn)單模型
這時(shí)候如果一個(gè)團(tuán)隊(duì)或一個(gè)公司中同時(shí)都有設(shè)計(jì)到大數(shù)據(jù)批量處理、交互式查詢、實(shí)時(shí)數(shù)據(jù)流處理這三個(gè)場(chǎng)景;這時(shí)候就會(huì)有一些問(wèn)題:
1、學(xué)習(xí)成本很高,每個(gè)框架都是不同的實(shí)現(xiàn)語(yǔ)言、不同的團(tuán)隊(duì)開(kāi)發(fā)的;
2、各個(gè)場(chǎng)景組合起來(lái)代價(jià)必然會(huì)很大;
3、各個(gè)框架中共享的中間數(shù)據(jù)共享與移動(dòng)成本高;
就在這時(shí)候UC Berkeley AMP推出了全新的大數(shù)據(jù)處理框架:Spark提供了全面、統(tǒng)一適用與不同場(chǎng)景的大數(shù)據(jù)處理需求(批量數(shù)據(jù)處理、交互式數(shù)據(jù)查詢、實(shí)時(shí)數(shù)據(jù)流處理、機(jī)器學(xué)習(xí));Spark不僅性能遠(yuǎn)勝于Hadoop而卻還兼容Hadoop生態(tài)系統(tǒng),Spark可以運(yùn)行在Hadoop HDFS之上提供爭(zhēng)強(qiáng) 功能,可以說(shuō)Spark替代了Hadoop MapReduce,但Spark依然兼容Hadoop中的YARN與Apache Mesos組件,現(xiàn)有Hadoop用戶可以很容易就遷移到Spark;
Spark提出了RDD(Resilient Distributed Datasets)這么一個(gè)全新的概念,RDD彈性分布式數(shù)據(jù)集是并行、容錯(cuò)的分布式數(shù)據(jù)結(jié)構(gòu);RDD可以持久化到硬盤或內(nèi)存當(dāng)中,為一個(gè)分區(qū)的數(shù)據(jù)集,分區(qū)的多少?zèng)Q定了并行計(jì)算的粒度;并且提供了一系列的操作RDD中的數(shù)據(jù):
1、創(chuàng)建操作(Creation Operation):RDD由SparkContext通過(guò)內(nèi)存數(shù)據(jù)或外部文件系統(tǒng)創(chuàng)建;
2、轉(zhuǎn)換操作(Transformation Operation):將RDD通過(guò)轉(zhuǎn)換操作變?yōu)榱硪粋€(gè)RDD,Spark提供了map、flatMap、filter等一系列的轉(zhuǎn)換操作;
3、控制操作(Control Operation):將RDD持久化到內(nèi)存或硬盤當(dāng)中,如cache將filterRDD緩存到內(nèi)存;
4、行動(dòng)操作:(Action Operation):Spark采用了惰性計(jì)算,對(duì)于任何行動(dòng)操作都會(huì)產(chǎn)生Spark Job運(yùn)行產(chǎn)生最終結(jié)果;提供了join、groupBy、count等操作,Spark中存在兩種操作產(chǎn)生的結(jié)果為Scala集合或者標(biāo)量與RDD保存到文件或數(shù)據(jù)庫(kù);
1、Spark結(jié)構(gòu)圖
Spark RDD:Spark RDD提供了一系列的操作接口,為不變的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)并存儲(chǔ)與內(nèi)存中使用DAG進(jìn)行任務(wù)規(guī)劃使更好的處理MapReduce類似的批處理;
Shark/Spark SQL:分布式SQL引擎,兼容Hive性能遠(yuǎn)比Hive高很多;
Spark Streaming:將數(shù)據(jù)流分解為一系列批處理作業(yè)使用Spark調(diào)度框架更好的支持?jǐn)?shù)據(jù)流操作,支持的數(shù)據(jù)輸入源有:Kafka、Flume等;
GraphX:兼容Pregel、GraphLab接口為基于Spark的圖計(jì)算框架;
MLlib:為Spark的機(jī)器學(xué)習(xí)算法庫(kù),支持常用的算法有:分類算法、推薦算法、聚類算法等等;
性能卓越、支持多種大數(shù)據(jù)處理模型、支持多種編程語(yǔ)言接口:Java、Scala、Python,許多大公司如IBM等大力支持推廣Spark的發(fā)展;
前面簡(jiǎn)單的介紹了Spark的一些概念還有Spark生態(tài)圈的一些情況,這里主要是介紹Spark運(yùn)行模式與Spark Standalone模式的部署;
在Spark中存在著多種運(yùn)行模式,可使用本地模式運(yùn)行、可使用偽分布式模式運(yùn)行、使用分布式模式也存在多種模式如:Spark Mesos模式、Spark YARN模式;
Spark Mesos模式:官方推薦模式,通用集群管理,有兩種調(diào)度模式:粗粒度模式(Coarse-grained Mode)與細(xì)粒度模式(Fine-grained Mode);
Spark YARN模式:Hadoop?YARN資源管理模式;
Standalone模式:?簡(jiǎn)單模式或稱獨(dú)立模式,可以單獨(dú)部署到一個(gè)集群中,無(wú)依賴任何其他資源管理系統(tǒng)。不使用其他調(diào)度工具時(shí)會(huì)存在單點(diǎn)故障,使用Zookeeper等可以解決;
Local模式:本地模式,可以啟動(dòng)本地一個(gè)線程來(lái)運(yùn)行job,可以啟動(dòng)N個(gè)線程或者使用系統(tǒng)所有核運(yùn)行job;
Standalone模式需要將Spark復(fù)制到集群中的每個(gè)節(jié)點(diǎn),然后分別啟動(dòng)每個(gè)節(jié)點(diǎn)即可;Spark Standalone模式的集群由Master與Worker節(jié)點(diǎn)組成,程序通過(guò)與Master節(jié)點(diǎn)交互申請(qǐng)資源,Worker節(jié)點(diǎn)啟動(dòng)Executor運(yùn)行;
這里使用了兩節(jié)點(diǎn)部署Spark集群:192.168.2.131、192.168.2.133,下面簡(jiǎn)稱為:133與131節(jié)點(diǎn);其中133節(jié)點(diǎn)既是Master節(jié)點(diǎn)同時(shí)又是Worker節(jié)點(diǎn),131節(jié)點(diǎn)為Worker節(jié)點(diǎn);
節(jié)點(diǎn)結(jié)構(gòu)圖
部署步驟:
一、
首先在133節(jié)點(diǎn)上下載Java、Scala與Spark并解壓到/usr/local目錄下,這里使用的Spark是帶有Hadoop的版本;
下載解壓到local
二、配置Java、Scala與Spark環(huán)境變量,這里把環(huán)境變量配置到/etc/profile文件中,請(qǐng)忽略Hadoop環(huán)境變量;
環(huán)境變量配置
三、測(cè)試Java、Scala是否配置成功,在終端輸入:java -version與scala -version
四、配置Spark環(huán)境變量,進(jìn)入Spark目錄下的conf目錄把slaves.template重命名為slaves,接著把spark-env.sh.template重命名為:spark-env.sh;
重命名
修改spark-env.sh文件,添加環(huán)境變量;
spark-env修改
五、
在133節(jié)點(diǎn)使用scp把下載好的Java、Scala、Spark發(fā)送到131節(jié)點(diǎn),并在131節(jié)點(diǎn)上重復(fù)以上所有步驟;
六、在兩個(gè)節(jié)點(diǎn)都完成以上所有步驟后開(kāi)始啟動(dòng)Spark,133節(jié)點(diǎn)既是Master又是Worker;
1、首先在133啟動(dòng)Spark,進(jìn)入Spark目錄的sbin目錄執(zhí)行./start-all.sh:
Master啟動(dòng)
使用jps命令發(fā)現(xiàn)存在Master與Worker進(jìn)程,說(shuō)明Spark已啟動(dòng)成功;
2、啟動(dòng)131節(jié)點(diǎn)的Spark,進(jìn)入Spark目錄的sbin目錄執(zhí)行:./start-slave.sh spark://192.168.2.133:7077
start-slave.sh后面的地址為Master節(jié)點(diǎn)的通信地址,指定當(dāng)前slave節(jié)點(diǎn)連接到的Master;
slave啟動(dòng):
使用jps命令,存在Worker進(jìn)程則說(shuō)明當(dāng)前的Spark Worker節(jié)點(diǎn)啟動(dòng)成功;
七、?Spark Web頁(yè)面
可以通過(guò)http://192.168.2.133:8080/ 地址查看到當(dāng)前Spark集群的信息,這地址為Master節(jié)點(diǎn)的地址;
SparkWeb:
參考資料:
http://spark.apache.org/docs/latest/spark-standalone.html
Spark中最核心的概念為RDD(Resilient Distributed DataSets)中文為:彈性分布式數(shù)據(jù)集,RDD為對(duì)分布式內(nèi)存對(duì)象的 抽象它表示一個(gè)被分區(qū)不可變且能并行操作的數(shù)據(jù)集;RDD為可序列化的、可緩存到內(nèi)存對(duì)RDD進(jìn)行操作過(guò)后還可以存到內(nèi)存中,下次操作直接把內(nèi)存中RDD作為輸入,避免了Hadoop?MapReduce的大IO操作;
Spark所要處理的任何數(shù)據(jù)都是存儲(chǔ)在RDD之中,目前兩種方式可以生成一個(gè)RDD:
1、從RDD進(jìn)行轉(zhuǎn)換操作
2、使用外部存儲(chǔ)系統(tǒng)創(chuàng)建,如:HDFS;
RDD支持兩種操作:
轉(zhuǎn)換(transformation operation)
轉(zhuǎn)換操作將一個(gè)RDD經(jīng)過(guò)操作后返回一個(gè)全新的RDD,轉(zhuǎn)換操是lazy(惰性)的這期間不會(huì)產(chǎn)生任何數(shù)據(jù)的計(jì)算;
轉(zhuǎn)換函數(shù)有:distinct、filter、map、flatMap、union、groupByKey等;
行動(dòng)(action operation)
每一個(gè)行動(dòng)操作都會(huì)觸發(fā)Spark Job進(jìn)行計(jì)算并返回最終的結(jié)果,行動(dòng)操作有這么幾類:返回標(biāo)量,count返回元素的個(gè)數(shù);返回Scala集合,task(n)返回0到n-1組成的集合;寫入外部存儲(chǔ),saveAsHadoopFile(path)存儲(chǔ)到HDFS;
行動(dòng)函數(shù)有:count、top、task、saveAsHadoopFile等;
RDD為不可變的數(shù)據(jù)集,可以使用轉(zhuǎn)換操作“修改”一個(gè)RDD,但這操作過(guò)后返回的是一個(gè)全新的RDD 原本RDD并沒(méi)有改變;
RDD狀態(tài)轉(zhuǎn)換圖
Spark RDD只支持粗粒度的操作,對(duì)一個(gè)RDD的操作都會(huì)被作用于該RDD的所有數(shù)據(jù);為了保證RDD的高可用性RDD通過(guò)使用Lineage(血統(tǒng))記錄了RDD演變流程(從其他RDD到當(dāng)前RDD所做的操作) 當(dāng)RDD分區(qū)數(shù)據(jù)丟失時(shí)可以通過(guò)Lineage的信息重新計(jì)算與恢復(fù)分區(qū)數(shù)據(jù),或進(jìn)行RDD的重建;
RDD的依賴關(guān)系(dependencies):
由于對(duì)RDD的操作都是粗粒度的一個(gè)轉(zhuǎn)換操作過(guò)后都會(huì)產(chǎn)生一個(gè)新的RDD,RDD之間會(huì)形成一個(gè)前后依賴關(guān)系;Spark中存在兩種依賴:窄依賴(Narrow Dependencies)、寬依賴(Wide Dependencies);
窄依賴(Narrow Dependencies):一個(gè)父RDD的分區(qū)只能被一個(gè)子RDD的一個(gè)分區(qū)使用;
寬依賴(Wide Dependencies):多個(gè)子RDD的分區(qū)依賴于一個(gè)父RDD的同一個(gè)分區(qū);
窄依賴的節(jié)點(diǎn)(RDD)關(guān)系如果流水一般,所以當(dāng)節(jié)點(diǎn)失敗后只需重新計(jì)算父節(jié)點(diǎn)的分區(qū)即可,寬依賴需要重新計(jì)算父節(jié)點(diǎn)的多個(gè)分區(qū)代價(jià)是非常昂貴的;
窄依賴Narrow
寬依賴Wide
參考資料:
http://www.cs.berkeley.edu/~matei/papers/2012/nsdi_spark.pdf
http://spark.apache.org/docs/latest/programming-guide.html
Spark支持Maven與SBT兩種編譯工具,這里使用了Maven進(jìn)行編譯打包;
在執(zhí)行make-distribution腳本時(shí)它會(huì)檢查本地是否已經(jīng)存在Maven還有當(dāng)前Spark所依賴的Scala版本,如果不存在它會(huì)自動(dòng)幫你下載到build目錄中并解壓使用;Maven源最好配置成OSChina的中央庫(kù),這下載依賴包比較快;
耐心等待,我編譯過(guò)多次所以沒(méi)有下載依賴包,大概半個(gè)小時(shí)左右編譯完成;注意:如果使用的是Java 1.8需要給JVM配置堆與非堆內(nèi)存,如:export MAVEN_OPTS="-Xmx1.5g -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=512m";
進(jìn)入Spark根目錄下,執(zhí)行:
./make-distribution.sh--tgz--tgz 參數(shù)是指編譯后生成tgz包? - PHadoop支持Hadoop -Pyarn :支持yarn -Phive :支持hive--with-tachyon:支持tachyon內(nèi)存文件系統(tǒng)-name:與--tgz一起用時(shí),name代替Hadoop版本號(hào)./make-distribution.sh--tgz --name 2.6.0 -Pyarn -Phadoop-2.6 -Phive
開(kāi)始編譯檢查本地環(huán)境,如不存在合適的Scala與Maven就在后臺(tái)下載;
編譯中:
編譯完成并打包生成tgz:
編譯完成后把生成的文件拷貝到當(dāng)前Spark的dist目錄中并且打包生成spark-1.5.3-SNAPSHOT-bin-2.2.0.tgz文件;
Spark執(zhí)行不少操作時(shí)都依賴于閉包函數(shù)的調(diào)用,此時(shí)如果閉包函數(shù)使用到了外部變量驅(qū)動(dòng)程序在使用行動(dòng)操作時(shí)傳遞到集群中各worker節(jié)點(diǎn)任務(wù)時(shí)就會(huì)進(jìn)行一系列操作:
1、驅(qū)動(dòng)程序使將閉包中使用變量封裝成對(duì)象,驅(qū)動(dòng)程序序列化對(duì)象,傳給worker節(jié)點(diǎn)任務(wù);
2、worker節(jié)點(diǎn)任務(wù)接收到對(duì)象,執(zhí)行閉包函數(shù);
由于使用外部變量勢(shì)必會(huì)通過(guò)網(wǎng)絡(luò)、序列化、反序列化,如外部變量過(guò)大或過(guò)多使用外部變量將會(huì)影響Spark程序的性能;
Spark提供了兩種類型的共享變量(Shared Variables):廣播變量(Broadcast Variables)、累加器(Accumulators );
廣播變量(Broadcast Variables)
Spark提供的廣播變量可以解決閉包函數(shù)引用外部大變量引起的性能問(wèn)題;廣播變量將只讀變量緩存在每個(gè)worker節(jié)點(diǎn)中,Spark使用了高效廣播算法分發(fā)變量從而提高通信性能;如直接在閉包函數(shù)中使用外部 變量該變量會(huì)緩存在每個(gè)任務(wù)(jobTask)中如果多個(gè)任務(wù)同時(shí)使用了一個(gè)大變量勢(shì)必會(huì)影響到程序性能;
廣播變量:每個(gè)worker節(jié)點(diǎn)中緩存一個(gè)副本,通過(guò)高效廣播算法提高傳輸效率,廣播變量是只讀的;
Spark Scala Api與Java Api默認(rèn)使用了Jdk自帶序列化庫(kù),通過(guò)使用第三方或使用自定義的序列化庫(kù)還可以進(jìn)一步提高廣播變量的性能;
廣播變量使用示例:
valsc = SparkContext("");valeigenValue = sc.bradcast(loadEigenValue())valeigen = computer.map{x =>valtemp = eigenValue.value? ? ...? ? ...}
左節(jié)點(diǎn)不使用廣播變量,右使用廣播變量
累加器(Accumulators)
累加器可以使得worker節(jié)點(diǎn)中指定的值聚合到驅(qū)動(dòng)程序中,如統(tǒng)計(jì)Spark程序執(zhí)行過(guò)程中的事件總數(shù)等;
valsc =newSparkContext(...)valfile = sc.textFile("xxx.txt")valeventCount = sc.accumulator(0,"EventAccumulator")//累加器初始值為0valformatEvent = file.flatMap(line => {if(line.contains("error")){? ? ? ? eventCount +=1}? ? })formatEvent.saveAsTextFile("eventData.txt")println("error event count : "+ eventCount);
在使用累加器(Accumulators)時(shí)需要注意,只有在行動(dòng)操作中才會(huì)觸發(fā)累加器,也就是說(shuō)上述代碼中由于flatMap()為轉(zhuǎn)換操作因?yàn)镾park惰性特征所以只用當(dāng)saveAsTextFile() 執(zhí)行時(shí)累加器才會(huì)被觸發(fā);累加器只有在驅(qū)動(dòng)程序中才可訪問(wèn),worker節(jié)點(diǎn)中的任務(wù)不可訪問(wèn)累加器中的值;
Spark原生支持了數(shù)字類型的的累加器如:Int、Double、Long、Float等;此外Spark還支持自定義累加器用戶可以通過(guò)繼承AccumulableParam特征來(lái)實(shí)現(xiàn)自定義的累加器此外Spark還提供了accumulableCollection()累加集合用于;創(chuàng)建累加器時(shí)可以使用名字也可以不是用名字,當(dāng)使用了名字時(shí)在Spark UI中可看到當(dāng)中程序中定義的累加器, 廣播變量存儲(chǔ)級(jí)別為MEMORY_AND_DISK;
Spark作為分布式的大數(shù)據(jù)處理框架必然或涉及到大量的作業(yè)調(diào)度,如果能夠理解Spark中的調(diào)度對(duì)我們編寫或優(yōu)化Spark程序都是有很大幫助的;
在Spark中存在轉(zhuǎn)換操作(Transformation Operation)與?行動(dòng)操作(Action Operation)兩種;而轉(zhuǎn)換操作只是會(huì)從一個(gè)RDD中生成另一個(gè)RDD且是lazy的,Spark中只有行動(dòng)操作(Action Operation)才會(huì)觸發(fā)作業(yè)的提交,從而引發(fā)作業(yè)調(diào)度;在一個(gè)計(jì)算任務(wù)中可能會(huì)多次調(diào)用 轉(zhuǎn)換操作這些操作生成的RDD可能存在著依賴關(guān)系,而由于轉(zhuǎn)換都是lazy所以當(dāng)行動(dòng)操作(Action Operation )觸發(fā)時(shí)才會(huì)有真正的RDD生成,這一系列的RDD中就存在著依賴關(guān)系形成一個(gè)DAG(Directed Acyclc Graph),在Spark中DAGScheuler是基于DAG的頂層調(diào)度模塊;
Application:使用Spark編寫的應(yīng)用程序,通常需要提交一個(gè)或多個(gè)作業(yè);
Job:在觸發(fā)RDD Action操作時(shí)產(chǎn)生的計(jì)算作業(yè)
Task:一個(gè)分區(qū)數(shù)據(jù)集中最小處理單元也就是真正執(zhí)行作業(yè)的地方
TaskSet:由多個(gè)Task所組成沒(méi)有Shuffle依賴關(guān)系的任務(wù)集
Stage:一個(gè)任務(wù)集對(duì)應(yīng)的調(diào)度階段 ,每個(gè)Job會(huì)被拆分成諾干個(gè)Stage
1.1 作業(yè)調(diào)度關(guān)系圖
這里根據(jù)Spark源碼跟蹤觸發(fā)Action操作時(shí)觸發(fā)的Job提交流程,Count()是RDD中的一個(gè)Action操作所以調(diào)用Count時(shí)會(huì)觸發(fā)Job提交;
在RDD源碼count()調(diào)用SparkContext的runJob,在runJob方法中根據(jù)partitions(分區(qū))大小創(chuàng)建Arrays存放返回結(jié)果;
RDD.scala/**
* Return the number of elements in the RDD.
*/defcount():Long= sc.runJob(this,Utils.getIteratorSize_).sumSparkContext.scaladef runJob[T,U:ClassTag](? rdd:RDD[T],func:(TaskContext, Iterator[T])=>U,? partitions:Seq[Int],? resultHandler: (Int,U) =>Unit):Unit= {? val callSite = getCallSite? val cleanedFunc = clean(func)logInfo("Starting job: "+ callSite.shortForm)if(conf.getBoolean("spark.logLineage",false)) {? ? logInfo("RDD's recursive dependencies:\n"+ rdd.toDebugString)? }? dagScheduler.runJob(rdd, cleanedFunc, partitions, callSite, resultHandler, localProperties.get)}
在SparkContext中將調(diào)用DAGScheduler的runJob方法提交作業(yè),DAGScheduler主要任務(wù)是計(jì)算作業(yè)與任務(wù)依賴關(guān)系,處理調(diào)用邏輯;DAGScheduler提供了submitJob與runJob方法用于 提交作業(yè),runJob方法會(huì)一直等待作業(yè)完成,submitJob則返回JobWaiter對(duì)象可以用于判斷作業(yè)執(zhí)行結(jié)果;
在runJob方法中將調(diào)用submitJob,在submitJob中把提交操作放入到事件循環(huán)隊(duì)列(DAGSchedulerEventProcessLoop)中;
def submitJob[T, U](? rdd:RDD[T],? func:(TaskContext, Iterator[T]) => U,? partitions:Seq[Int],? callSite:CallSite,? resultHandler:(Int, U) => Unit,? properties:Properties): JobWaiter[U] = {? ? ? ......? ? ? ? eventProcessLoop.post(JobSubmitted(? ? ? jobId, rdd, func2, partitions.toArray, callSite, waiter,? ? ? SerializationUtils.clone(properties)))? ? ? ......? }
在事件循環(huán)隊(duì)列中將調(diào)用eventprocessLoop的onReceive方法;
提交作業(yè)時(shí)DAGScheduler會(huì)從RDD依賴鏈尾部開(kāi)始,遍歷整個(gè)依賴鏈劃分調(diào)度階段;劃分階段以ShuffleDependency為依據(jù),當(dāng)沒(méi)有ShuffleDependency時(shí)整個(gè)Job 只會(huì)有一個(gè)Stage;在事件循環(huán)隊(duì)列中將會(huì)調(diào)用DAGScheduler的handleJobSubmitted方法,此方法會(huì)拆分Stage、提交Stage;
private[scheduler] def handleJobSubmitted(jobId:Int,? finalRDD:RDD[_],func:(TaskContext, Iterator[_])=>_,? partitions:Array[Int],? callSite:CallSite,? listener:JobListener,? properties:Properties) {varfinalStage:ResultStage= null......? finalStage = newResultStage(finalRDD,func,partitions,jobId,callSite)......valjob=newActiveJob(jobId, finalStage, callSite, listener, properties)......val jobSubmissionTime = clock.getTimeMillis()jobIdToActiveJob(jobId) = jobactiveJobs += jobfinalStage.setActiveJob(job)val stageIds = jobIdToStageIds(jobId).toArrayval stageInfos = stageIds.flatMap(id => stageIdToStage.get(id).map(_.latestInfo))listenerBus.post(SparkListenerJobStart(job.jobId, jobSubmissionTime, stageInfos, properties))submitStage(finalStage)submitWaitingStages()}
在提交Stage時(shí)會(huì)先調(diào)用getMissingParentStages獲取父階段Stage,迭代該階段所依賴的父調(diào)度階段如果存在則先提交該父階段的Stage 當(dāng)不存在父Stage或父Stage執(zhí)行完成時(shí)會(huì)對(duì)當(dāng)前Stage進(jìn)行提交;
privatedefsubmitStage(stage:Stage) {valjobId = activeJobForStage(stage)if(jobId.isDefined) {if(!waitingStages(stage) && !runningStages(stage) && !failedStages(stage)) {valmissing = getMissingParentStages(stage).sortBy(_.id)if(missing.isEmpty) {? ? ? ? submitMissingTasks(stage, jobId.get)? ? ? }else{for(parent <- missing) {? ? ? ? ? submitStage(parent)? ? ? ? }? ? ? ? waitingStages += stage? ? ? }? ? }? }? ......}
參考資料:
http://spark.apache.org/docs/latest/
Scala 的詳細(xì)介紹:請(qǐng)點(diǎn)這里
Scala 的下載地址:請(qǐng)點(diǎn)這里