Spark基本概念快速入門

Spark集群

一組計算機的集合,每個計算機節點作為獨立的計算資源,又可以虛擬出多個具備計算能力的虛擬機,這些虛擬機是集群中的計算單元。Spark的核心模塊專注于調度和管理虛擬機之上分布式計算任務的執行,集群中的計算資源則交給Cluster Manager這個角色來管理,Cluster Manager可以為自帶的Standalone、或第三方的Yarn和Mesos。
Cluster Manager一般采用Master-Slave結構。以Yarn為例,部署ResourceManager服務的節點為Master,負責集群中所有計算資源的統一管理和分配;部署NodeManager服務的節點為Slave,負責在當前節點創建一個或多個具備獨立計算能力的JVM實例,在Spark中,這些節點也叫做Worker。
另外還有一個Client節點的概念,是指用戶提交Spark Application時所在的節點。

Application

用戶自己寫的Spark應用程序,批處理作業的集合。Application的main方法為應用程序的入口,用戶通過Spark的API,定義了RDD和對RDD的操作。這里可以參考一段定義:

可以認為應用是多次批量計算組合起來的過程,在物理上可以表現為你寫的程序包+部署配置。應用的概念類似于計算機中的程序,它只是一個藍本,尚沒有運行起來?!?a target="_blank" rel="nofollow">spark學習筆記三:spark原理介紹

SparkContext

Spark最重要的API,用戶邏輯與Spark集群主要的交互接口,它會和Cluster Master交互,包括向它申請計算資源等。

Driver和Executor

Spark在執行每個Application的過程中會啟動Driver和Executor兩種JVM進程:

  • Driver進程為主控進程,負責執行用戶Application中的main方法,提交Job,并將Job轉化為Task,在各個Executor進程間協調Task的調度。
  • 運行在Worker上的Executor進程負責執行Task,并將結果返回給Driver,同時為需要緩存的RDD提供存儲功能。


圖片來源 - Spark Cluster Mode Overview

Spark有Client和Cluster兩種部署Application的模式,Application以以Client模式部署時,Driver運行于Client節點,而以Cluster模式部署時,Driver運行于Worker節點,與Executor一樣由Cluster Manager啟動。

RDD

彈性分布式數據集,只讀分區記錄的集合,Spark對所處理數據的基本抽象。Spark中的計算可以簡單抽象為對RDD的創建、轉換和返回操作結果的過程:

  • 創建
    通過加載外部物理存儲(如HDFS)中的數據集,或Application中定義的對象集合(如List)來創建。RDD在創建后不可被改變,只可以對其執行下面兩種操作。
  • 轉換(Transformation)
    對已有的RDD中的數據執行計算進行轉換,而產生新的RDD,在這個過程中有時會產生中間RDD。Spark對于Transformation采用惰性計算機制,遇到Transformation時并不會立即計算結果,而是要等遇到Action時一起執行。
  • 行動(Action)
    對已有的RDD中的數據執行計算產生結果,將結果返回Driver程序或寫入到外部物理存儲。在Action過程中同樣有可能生成中間RDD。

Partition(分區)

一個RDD在物理上被切分為多個Partition,即數據分區,這些Partition可以分布在不同的節點上。Partition是Spark計算任務的基本處理單位,決定了并行計算的粒度,而Partition中的每一條Record為基本處理對象。例如對某個RDD進行map操作,在具體執行時是由多個并行的Task對各自分區的每一條記錄進行map映射。

Dependency(依賴)

對RDD的Transformation或Action操作,讓RDD產生了父子依賴關系(事實上,Transformation或Action操作生成的中間RDD也存在依賴關系),這種依賴分為寬依賴和窄依賴兩種:

  • NarrowDependency (窄依賴)
    parent RDD中的每個Partition最多被child RDD中的一個Partition使用。讓RDD產生窄依賴的操作可以稱為窄依賴操作,如map、union。
  • WideDependency (或ShuffleDependency,寬依賴)
    parent RDD中的每個Partition被child RDD中的多個Partition使用,這時會依據Record的key進行數據重組,這個過程即為Shuffle(洗牌)。讓RDD產生寬依賴的操作可以稱為寬依賴操作,如reduceByKey, groupByKey。

Spark根據用戶Application中的RDD的轉換和行動,生成RDD之間的依賴關系,RDD之間的計算鏈構成了RDD的血統(Lineage),同時也生成了邏輯上的DAG(有向無環圖)。每一個RDD都可以根據其依賴關系一級一級向前回溯重新計算,這便是Spark實現容錯的一種手段:

RDD的每次轉換都會生成一個新的RDD,所以RDD之間就會形成類似于流水線一樣的前后依賴關系。在部分分區數據丟失時,Spark可以通過這個依賴關系重新計算丟失的分區數據,而不是對RDD的所有分區進行重新計算。
——《Spark技術內幕》-第3章-RDD實現詳解

Job

在一個Application中,以Action為劃分邊界的Spark批處理作業。前面提到,Spark采用惰性機制,對RDD的創建和轉換并不會立即執行,只有在遇到第一個Action時才會生成一個Job,然后統一調度執行。一個Job包含N個Transformation和1個Action。

Shuffle

有一部分Transformation或Action會讓RDD產生寬依賴,這樣過程就像是將父RDD中所有分區的Record進行了“洗牌”(Shuffle),數據被打散重組,如屬于Transformation操作的join,以及屬于Action操作的reduce等,都會產生Shuffle。

Stage

一個Job中,以Shuffle為邊界劃分出的不同階段。每個階段包含一組可以被串行執行的窄依賴或寬依賴操作:

用戶提交的計算任務是一個由RDD構成的DAG,如果RDD在轉換的時候需要做Shuffle,那么這個Shuffle的過程就將這個DAG分為了不同的階段(即Stage)。由于Shuffle的存在,不同的Stage是不能并行計算的,因為后面Stage的計算需要前面Stage的Shuffle的結果。
——《Spark技術內幕》-第4章-Scheduler模塊詳解

在對Job中的所有操作劃分Stage時,一般會按照倒序進行,即從Action開始,遇到窄依賴操作,則劃分到同一個執行階段,遇到寬依賴操作,則劃分一個新的執行階段,且新的階段為之前階段的parent,然后依次類推遞歸執行。child Stage需要等待所有的parent Stage執行完之后才可以執行,這時Stage之間根據依賴關系構成了一個大粒度的DAG。
在一個Stage內,所有的操作以串行的Pipeline的方式,由一組Task完成計算。

Task

對一個Stage之內的RDD進行串行操作的計算任務。每個Stage由一組并發的Task組成(即TaskSet),這些Task的執行邏輯完全相同,只是作用于不同的Partition。一個Stage的總Task的個數由Stage中最后的一個RDD的Partition的個數決定。

Spark Driver會根據數據所在的位置分配計算任務,即把所有Task根據其Partition所在的位置分配給相應的Executor,以盡量減少數據的網絡傳輸(這也就是所謂的移動數據不如移動計算)。一個Executor內同一時刻可以并行執行的Task數由總CPU數/每個Task占用的CPU數決定,即spark.executor.cores / spark.task.cpus

Task分為ShuffleMapTask和ResultTask兩種,位于最后一個Stage的Task為ResultTask,其他階段的屬于ShuffleMapTask。

Persist & Checkpoint

Persist

通過RDD的persist方法,可以將RDD的分區數據持久化在內存或硬盤中,通過cache方法則是緩存到內存。這里的persist和cache是一樣的機制,只不過cache是使用默認的MEMORY_ONLY的存儲級別對RDD進行persist,故“緩存”也就是一種“持久化”。
前面提到,只有觸發了一個Action之后,Spark才會提交Job進行真正的計算。所以RDD只有經過一次Action之后,才能將RDD持久化,然后在Job間共享,即如果兩個Job用到了相同的RDD,那么可以在第一個Job中對這個RDD進行緩存,在第二個Job中就避免了RDD的重新計算。持久化機制使需要訪問重復數據的Application運行地更快,是能夠提升Spark運算速度的一個重要功能。

Checkpoint

調用RDD的checkpoint方法,可以將RDD保存到外部存儲中,如硬盤或HDFS。Spark引入checkpoint機制,是因為持久化的RDD的數據有可能丟失或被替換,checkpoint可以在這時候發揮作用,避免重新計算。
創建checkpoint是在當前Job完成后,由另外一個專門的Job完成:

也就是說需要checkpoint的RDD會被計算兩次。因此,在使用rdd.checkpoint()的時候,建議加上rdd.cache(),這樣第二次運行的Job久不用再去計算該rdd了。
——Apache Spark的設計與實現- Cache和Checkpoint功能

一個Job在開始處理RDD的Partition時,或者更準確點說,在Executor中運行的任務在獲取Partition數據時,會先判斷是否被持久化,在沒有命中時再判斷是否保存了checkpoint,如果沒有讀取到則會重新計算該Partition。

案例分析

這里借用@JerryLeadComplexJob案例做一下分析:

object complexJob {
  def main(args: Array[String]) {

    val sc = new SparkContext("local", "ComplexJob test")

    val data1 = Array[(Int, Char)](
      (1, 'a'), (2, 'b'),
      (3, 'c'), (4, 'd'),
      (5, 'e'), (3, 'f'),
      (2, 'g'), (1, 'h'))
    val rangePairs1 = sc.parallelize(data1, 3)

    val hashPairs1 = rangePairs1.partitionBy(new HashPartitioner(3))


    val data2 = Array[(Int, String)]((1, "A"), (2, "B"),
      (3, "C"), (4, "D"))

    val pairs2 = sc.parallelize(data2, 2)
    val rangePairs2 = pairs2.map(x => (x._1, x._2.charAt(0)))


    val data3 = Array[(Int, Char)]((1, 'X'), (2, 'Y'))
    val rangePairs3 = sc.parallelize(data3, 2)


    val rangePairs = rangePairs2.union(rangePairs3)


    val result = hashPairs1.join(rangePairs)

    result.foreachWith(i => i)((x, i) => println("[result " + i + "] " + x))

    println(result.toDebugString)
  }
}

作者在這個例子中主要定義了一個對RDD的union和join操作,主要的RDD之間的關系如下圖所示:


Job的物理執行圖:


圖片來源 - Job 物理執行圖

參考作者畫的物理執行圖,我們可以觀察到:

  • 該Application僅有一個Job,由foreachWith這個Action觸發。
  • 這個Job中有三個Stage,partitionBy操作對RDD重新分區產生了Shuffle,是劃分Stage0和Stage1的邊界。join操作則是Stage2和Stage0的邊界。
  • 每個Stage的Task總數等于該階段的最后一個RDD的Partition個數。
  • 每個Task都是串行執行一個Stage內的所有操作。
  • Transformation操作的過程中會產生中間RDD。

參考資料

  1. 《Spark技術內幕:深入解析Spark內核架構于實現原理》,張安站
  2. Apache Spark的設計與實現 (強烈推薦)
  3. spark學習筆記三:spark原理介紹
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容