Spark運行模式
Spark 的運行模式多種多樣、靈活多變,部署在單機上時,既可以用本地模式運行,也可以用偽分布式模式運行,而當以分布式集群的方式部署時,也有眾多的運行模式可以供選擇,這取決于集群的實際情況,底層的資源調度既可以依賴于外部的資源調度框架,也可以使用 Spark 內建的 Standalone 模式。對于外部資源調度框架的支持,包括Mesos 模式,以及Hadoop YARN 模式。
在實際應用中,Spark 應用程序的運行模式取決于傳遞給 SparkContext 的 MASTER 環境變量的值,個別模式還需要依賴輔助的程序接口來配合使用,目前所支持的 MASTER 環境變量由特定的字符串或 URL 所組成。如下:
local(本地模式):常用于本地開發測試,本地還分為local單線程和local-cluster多線程:
- Local[N]:本地模式,使用 N 個線程。
- Local[*]:還是本地模式,但是用了系統中所有的核。
- Local[N,M]:這里有兩個參數,第一個代表的是用到的核個數;第二個參數代表的是容許該作業失敗M次。上面的幾種模式沒有指定M參數,其默認值都是1。
- Local Cluster[Worker,core,Memory]:偽分布式模式,可以配置所需要啟動的虛擬工作節點的數量,以及每個工作節點所管理的 CPU 數量和內存尺寸。
cluster(集群模式):master-slave模式,Master服務(YARN ResourceManager,Mesos master和Spark standalone master)決定哪些application可以運行,什么時候運行以及哪里去運行。而slave服務( YARN NodeManager,Mesos slave和Spark standalone slave)實際上運行executor進程。
- Spark://hostname:port : Standalone模式,需要部署 Spark 到相關節點,URL 為 Spark Master 主機地址和端口。部署Standalone模式的集群僅需把編譯好的Spark發布版本分發到各節點,部署路徑盡量一致,且配置文件相同。
- Mesos://hostname:port : Mesos模式,需要部署 Spark 和 Mesos 到相關節點,URL 為 Mesos 主機地址和端口。
- YARN standalone/Yarn cluster : YARN 模式一,主程序邏輯和任務都運行在YARN集群中。用于集群生產模式。
-
YARN client : YARN 模式二,主程序邏輯運行在本地,具體任務運行在YARN集群中。主要用于與用戶交互調試模式,可以快速地看到application的輸出。spark-shell和pyspark必須要使用yarn-client模式。
二者主要區別是Driver的運行位置。
spark yarn-client.jpg
spark yarn-cluster.jpg
Spark架構中的基本組件
- ClusterManager:在Standalone模式中即為Master(主節點),控制整個集群,監控Worker。在YARN、Mesos模式中擔任資源管理器。
- Worker:從節點,負責控制計算節點,啟動Executor或Driver。在YARN模式中為NodeManager,負責計算節點的控制。
- Driver:運行Application的main()函數并創建SparkContext。
- Executor:執行器,在worker node上執行任務的組件、用于啟動線程池運行任務。不同的Spark應用程序擁有獨立的一組Executors。
- SparkContext:整個應用的上下文,控制應用的生命周期。
- RDD:Spark的基本計算單元,一組RDD可形成執行的有向無環圖RDD Graph。
- Task:運行于Executor中的任務單元,Spark應用程序最終被劃分為經過優化后的多個任務的集合。
- Job:由多個任務構建的并行計算任務,具體為Spark中的action操作,如collect,save等)。
- Stage:每個job將被拆分為更小的task集合,這些任務集合被稱為stage,各stage相互獨立(類似于MapReduce中的map stage和reduce stage),由于它由多個task集合構成,因此也稱為TaskSet。
- DAG Scheduler:根據作業(Job)構建基于Stage的DAG,并提交Stage給TaskScheduler。
- TaskScheduler:將任務(Task)分發給Executor執行。
- SparkEnv:線程級別的上下文,存儲運行時的重要組件的引用。
其中SparkEnv內創建并包含如下一些重要組件的引用:
- MapOutPutTracker:負責Shuffle元信息的存儲。
- BroadcastManager:負責廣播變量的控制與元信息的存儲。
- BlockManager:負責存儲管理、創建和查找塊。
- MetricsSystem:監控運行時性能指標信息。
- SparkConf:負責存儲配置信息。
彈性分布式數據集(RDD)
- RDD設計目標
RDD用于支持在并行計算時能夠高效地利用中間結果,支持更簡單的編程模型,同時也具有像MapReduce等并行計算框架的高容錯性、能夠高效地進行調度及可擴展性。RDD的容錯通過記錄RDD轉換操作的lineage關系來進行,lineage記錄了RDD的家族關系,當出現錯誤的時候,直接通過lineage進行恢復。RDD最合數據挖掘,機器學習及圖計算等涉及到迭代計算的場景,基于內存能夠極大地提升其在分布式環境下的執行效率。RDD不適用于諸如分布式爬蟲等需要頻繁更新共享狀態的任務。
spark-shell中如何查看RDD的Lineage:
//textFile讀取hdfs根目錄下的README.md文件,然后篩選出所有包括Spark的行
scala> val rdd2=sc.textFile("/README.md").filter(line => line.contains("Spark"))
rdd2: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[2] at filter at <console>:21
//toDebugString方法會打印出RDD的家族關系
//可以看到textFile方法會生成兩個RDD,分別是HadoopRDD、MapPartitionsRDD,而filter同時也會生成新的MapPartitionsRDD
scala> rdd2.toDebugString
15/09/20 01:35:27 INFO mapred.FileInputFormat: Total input paths to process : 1
res0: String =
(2) MapPartitionsRDD[2] at filter at <console>:21 []
| MapPartitionsRDD[1] at textFile at <console>:21 []
| /README.md HadoopRDD[0] at textFile at <console>:21 []
- RDD抽象
RDD在Spark中是一個只讀的(val類型)、經過分區的記錄集合。
兩種創建方式:從存儲系統中創建[本地/分布式/內存文件系統]或者從其它RDD中創建。
1.從HDFS中創建RDD
scala> sc.textFile("/README.md")
res1: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[4] at textFile at <console>:22
2.從內存中創建RDD
//內存中定義了一個數組
scala> val data = Array(1, 2, 3, 4, 5)
data: Array[Int] = Array(1, 2, 3, 4, 5)
//通過parallelize方法創建ParallelCollectionRDD
scala> val distData = sc.parallelize(data)
distData: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[5] at parallelize at <console>:23
3.從其它RDD創建新的RDD
//filter函數將distData RDD轉換成新的RDD
scala> val distDataFiletered=distData.filter(e=>e>2)
distDataFiletered: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[6] at filter at <console>:25
//觸發action操作,注意collect只適合數據量較少時使用
scala> distDataFiltered.collect
res3: Array[Int] = Array(3, 4, 5)
-
RDD的窄依賴與寬依賴
RDD經過transformation操作后會生成新的RDD,前一個RDD與tranformation操作后的RDD構成了lineage關系,也即后一個RDD與前一個RDD存在一定的依賴關系,根據tranformation操作后RDD與父RDD中的分區對應關系,可以將依賴分為兩種:寬依賴(wide dependency)和窄依賴(narrow dependency),如下圖:
dependency.png
圖中的實線空心矩形代表一個RDD,實線空心矩形中的帶陰影的小矩形表示分區(partition)。從上圖中可以看到, map、filter、union等transformation操作后的RDD僅依賴于父RDD的固定分區,它們是窄依賴的;而groupByKey后的RDD的分區與父RDD所有的分區都有依賴關系,此時它們就是寬依賴的。join操作存在兩種情況,如果分區僅僅依賴于父RDD的某一分區,則是窄依賴的,否則就是寬依賴。
RDD API:http://blog.csdn.net/pelick/article/details/44922619
reduceByKey和aggregateByKey算子都會使用用戶自定義的函數對每個節點本地的相同key進行預聚合,而groupByKey算子不會進行map-side預聚合(類似于MapReduce中的本地combiner)