??Spark一個非常重要的特性就是共享變量。
??默認情況下,如果在一個算子的函數(shù)中使用到了某個外部的變量,那么這個變量的值會被拷貝到每個task中,此時每個task只能操作自己的那份變量副本。如果多個task想要共享某個變量,那么這種方式是做不到的。
??Spark為此提供了兩種共享變量,一種是Broadcast Variable(廣播變量),另一種是Accumulator(累加變量)。Broadcast Variable會將用到的變量,僅僅為每個節(jié)點拷貝一份,即每個Executor拷貝一份,更大的用途是優(yōu)化性能,減少網(wǎng)絡(luò)傳輸以及內(nèi)存損耗。Accumulator則可以讓多個task共同操作一份變量,主要可以進行累加操作。Broadcast Variable是共享只讀變量,task不能去修改它,而Accumulator可以讓多個task操作一個變量。
廣播變量
??廣播變量允許編程者在每個Executor上保留外部數(shù)據(jù)的只讀變量,而不是給每個任務(wù)發(fā)送一個副本。


??Spark還嘗試使用高效的廣播算法分發(fā)廣播變量,以降低通信成本。
??Spark提供的Broadcast Variable是只讀的,并且在每個Executor上只會有一個副本,而不會為每個task都拷貝一份副本,因此,它的最大作用,就是減少變量到各個節(jié)點的網(wǎng)絡(luò)傳輸消耗,以及在各個節(jié)點上的內(nèi)存消耗。此外,Spark內(nèi)部也使用了高效的廣播算法來減少網(wǎng)絡(luò)消耗。
??可以通過調(diào)用SparkContext的broadcast()方法來針對每個變量創(chuàng)建廣播變量。然后在算子的函數(shù)內(nèi),使用到廣播變量時,每個Executor只會拷貝一份副本了,每個task可以使用廣播變量的value()方法獲取值。

??之后Executor會通過BlockManager向Driver拉取廣播變量,然后提供給task進行使用,如下圖所示:

??廣播大變量是Spark中常用的基礎(chǔ)優(yōu)化方法,通過減少內(nèi)存占用實現(xiàn)任務(wù)執(zhí)行性能的提升。
累加器
??累加器(accumulator):Accumulator是僅僅被相關(guān)操作累加的變量,因此可以在并行中被有效地支持。它們可用于實現(xiàn)計數(shù)器(如MapReduce)或總和計數(shù)。
??Accumulator是存在于Driver端的,集群上運行的task進行Accumulator的累加,隨后把值發(fā)到Driver端,在Driver端匯總(Spark UI在SparkContext創(chuàng)建時被創(chuàng)建,即在Driver端被創(chuàng)建,因此它可以讀取Accumulator的數(shù)值),由于Accumulator存在于Driver端,從節(jié)點讀取不到Accumulator的數(shù)值。
??Spark提供的Accumulator主要用于多個節(jié)點對一個變量進行共享性的操作。Accumulator只提供了累加的功能,但是卻給我們提供了多個task對于同一個變量并行操作的功能,但是task只能對Accumulator進行累加操作,不能讀取它的值,只有Driver程序可以讀取Accumulator的值。
