什麼是Spark?
Spark是一個開源框架,是基於內存計算的大數據並行計算框架。
Spark架構
並行化是將工作負載分在不同線程或不同節點上執行的子任務,Spark的工作負載劃分有RDD分區決定。
RDD:是彈性分佈式數據集。
Spark工作原理
Master是由四大部分組成(RDD Graph,Scheduler,Block Tracker以及Shuffle Tracker)
編寫程序提交到Master上,
啓動RDD Graph就是DAG,它會提交給Task Scheduler任務調度器等待調度執行
具體執行時,Task Scheduler會把任務提交到Worker節點上
Block Tracker用於記錄計算數據在Worker節點上的塊信息
Shuffle Blocker用於記錄RDD在計算過程中遇到Shuffle過程時會進行物化,Shuffle Tracker用於記錄這些物化的RDD的存放信息
RDD Graph
RDD Graph即DAG:
每個RDD由四個分區組成,每個分區分配一個任務執行,
綠色框表示實施RDD操作後的數據集。
Stage
由於shuffle依賴必須等RDD的parent RDD partition數據全部ready之後才能開始計算,因此spark的設計是讓parent RDD將結果寫在本地,完全寫完之後,通知後面的RDD。後面的RDD則首先去讀之前的本地數據作爲input,然後進行運算。
由於上述特性,將shuffle依賴就必須分爲兩個階段(stage)去做:
第一個階段(stage)需要把結果shuffle到本地,例如reduceByKey,首先要聚合某個key的所有記錄,才能進行下一步的reduce計算,這個匯聚的過程就是shuffle
第二個階段(stage)則讀入數據進行處理。
同一個stage裏面的task是可以併發執行的,下一個stage要等前一個stage ready
(和mapreduce的reduce需要等map過程ready 一脈相承)
(爲什麼要寫在本地:後面的RDD多個partition都要去讀這個信息,如果放到內存,如果出現數據丟失,後面的所有步驟全部不能進行,違背了之前所說的需要parent RDD partition數據全部ready的原則。爲什麼要保證parent RDD要ready,如下例,如果有一個partition未生成或者在內存中丟失,那麼直接導致計算結果是完全錯誤的:
寫到文件中更加可靠。Shuffle會生成大量臨時文件,以免錯誤時重新計算,其使用的本地磁盤目錄由spark.local.dir指定,緩存到磁盤的RDD數據。最好將這個屬性設定爲訪問速度快的本地磁盤。可以配置多個路徑到多個磁盤,增加IO帶寬
在Spark 1.0 以後,SPARK_LOCAL_DIRS(Standalone, Mesos) or LOCAL_DIRS (YARN)參數會覆蓋這個配置。比如Spark On YARN的時候,Spark Executor的本地路徑依賴於Yarn的配置,而不取決於這個參數。)
對於transformation操作,以shuffle依賴爲分隔,分爲不同的Stages。
窄依賴------>tasks會歸併在同一個stage中,(相同節點上的task運算可以像pipeline一樣順序執行,不同節點並行計算,互不影響)
shuffle依賴------>前後拆分爲兩個stage,前一個stage寫完文件後下一個stage才能開始
action操作------>和其他tasks會歸併在同一個stage(在沒有shuffle依賴的情況下,生成默認的stage,保證至少一個stage)
寬窄依賴
RDD依賴關係,也就是有依賴的RDD之間的關係,比如RDD1------->RDD2(RDD1生成RDD2),RDD2依賴於RDD1。這裏的生成也就是RDDtransformation操作
窄依賴(也叫narrow依賴)
從父RDD角度看:一個父RDD只被一個子RDD分區使用。父RDD的每個分區最多隻能被一個Child RDD的一個分區使用
從子RDD角度看:依賴上級RDD的部分分區 精確知道依賴的上級RDD分區,會選擇和自己在同一節點的上級RDD分區,沒有網絡IO開銷,高效。如map,flatmap,filter
寬依賴(也叫shuffle依賴/wide依賴)
從父RDD角度看:一個父RDD被多個子RDD分區使用。父RDD的每個分區可以被多個Child RDD分區依賴
從子RDD角度看:依賴上級RDD的所有分區 無法精確定位依賴的上級RDD分區,相當於依賴所有分區(例如reduceByKey) 計算就涉及到節點間網絡傳輸
Spark之所以將依賴分爲narrow和 shuffle:
(1) narrow dependencies可以支持在同一個集羣Executor上,以pipeline管道形式順序執行多條命令,例如在執行了map後,緊接着執行filter。分區內的計算收斂,不需要依賴所有分區的數據,可以並行地在不同節點進行計算。所以它的失敗恢復也更有效,因爲它只需要重新計算丟失的parent partition即可,
(2)shuffle dependencies 則需要所有的父分區都是可用的,必須等RDD的parent partition數據全部ready之後才能開始計算,可能還需要調用類似MapReduce之類的操作進行跨節點傳遞。從失敗恢復的角度看,shuffle dependencies 牽涉RDD各級的多個parent partition。
以wordcount爲例
1、新建一個scala project
2、導入包(主要用以下5個包)
sparksql
sql-mapping-mr
sparkStreaming-及時處理
sparkMLlib-機器學習
sparkGraphx-圖計算
3、更改scala版本,右擊項目——>configure Build Path——>Edit
4、新建一個object scala
import org.apache.spark.SparkContext
import org.apache.spark.SparkConf
import org.apache.spark.SparkConf
object wordCount {
def main(args: Array[String]):Unit = {
// System.setProperty("hadoop.home.dir", "C://Users//Administrator.DESKTOP-T63BNEF//Desktop//all folder//hadoop-2.6.5");
//spark處理---併發迭代大數據
//RDD.map word->(w,1)
//rdd.reduce->w->sum 1
//1.sc
var conf = new SparkConf()
conf.setMaster("local[*]").setAppName("hello")
var sc = new SparkContext(conf)
sc.setLogLevel("WARN");
//2.sc.textFile ->RDD
var path = "src/data/123" // "src/data/123"爲需要計算的文本文件
var filedata_rdd = sc.textFile(path,2)
var words_rdd=filedata_rdd
.flatMap(_.split("\\W+"))
.map(x=>(x,1))
.reduceByKey(_+_)
.map(_.swap)
.sortByKey(false)
// words_rdd.foreach(println)
print(filedata_rdd.count())
words_rdd.foreach{line=>
println("word="+line._1+" ,num="+line._2)
}
println("end....")
}
}
測試文本數據:
運行結果: