??Spark一個(gè)非常重要的特性就是共享變量潜叛。
??默認(rèn)情況下,如果在一個(gè)算子的函數(shù)中使用到了某個(gè)外部的變量适袜,那么這個(gè)變量的值會(huì)被拷貝到每個(gè)task中趁尼,此時(shí)每個(gè)task只能操作自己的那份變量副本。如果多個(gè)task想要共享某個(gè)變量嚎尤,那么這種方式是做不到的荔仁。
??Spark為此提供了兩種共享變量,一種是Broadcast Variable(廣播變量)芽死,另一種是Accumulator(累加變量)乏梁。Broadcast Variable會(huì)將用到的變量,僅僅為每個(gè)節(jié)點(diǎn)拷貝一份关贵,即每個(gè)Executor拷貝一份遇骑,更大的用途是優(yōu)化性能,減少網(wǎng)絡(luò)傳輸以及內(nèi)存損耗揖曾。Accumulator則可以讓多個(gè)task共同操作一份變量落萎,主要可以進(jìn)行累加操作。Broadcast Variable是共享只讀變量炭剪,task不能去修改它练链,而Accumulator可以讓多個(gè)task操作一個(gè)變量。
廣播變量
??廣播變量允許編程者在每個(gè)Executor上保留外部數(shù)據(jù)的只讀變量奴拦,而不是給每個(gè)任務(wù)發(fā)送一個(gè)副本媒鼓。
??Spark還嘗試使用高效的廣播算法分發(fā)廣播變量,以降低通信成本晾剖。
??Spark提供的Broadcast Variable是只讀的锉矢,并且在每個(gè)Executor上只會(huì)有一個(gè)副本,而不會(huì)為每個(gè)task都拷貝一份副本齿尽,因此沽损,它的最大作用,就是減少變量到各個(gè)節(jié)點(diǎn)的網(wǎng)絡(luò)傳輸消耗循头,以及在各個(gè)節(jié)點(diǎn)上的內(nèi)存消耗绵估。此外炎疆,Spark內(nèi)部也使用了高效的廣播算法來減少網(wǎng)絡(luò)消耗。
??可以通過調(diào)用SparkContext的broadcast()方法來針對(duì)每個(gè)變量創(chuàng)建廣播變量国裳。然后在算子的函數(shù)內(nèi)形入,使用到廣播變量時(shí),每個(gè)Executor只會(huì)拷貝一份副本了缝左,每個(gè)task可以使用廣播變量的value()方法獲取值亿遂。
??之后Executor會(huì)通過BlockManager向Driver拉取廣播變量是越,然后提供給task進(jìn)行使用耳舅,如下圖所示:
??廣播大變量是Spark中常用的基礎(chǔ)優(yōu)化方法,通過減少內(nèi)存占用實(shí)現(xiàn)任務(wù)執(zhí)行性能的提升倚评。
累加器
??累加器(accumulator):Accumulator是僅僅被相關(guān)操作累加的變量浦徊,因此可以在并行中被有效地支持。它們可用于實(shí)現(xiàn)計(jì)數(shù)器(如MapReduce)或總和計(jì)數(shù)蔓纠。
??Accumulator是存在于Driver端的辑畦,集群上運(yùn)行的task進(jìn)行Accumulator的累加吗蚌,隨后把值發(fā)到Driver端腿倚,在Driver端匯總(Spark UI在SparkContext創(chuàng)建時(shí)被創(chuàng)建,即在Driver端被創(chuàng)建蚯妇,因此它可以讀取Accumulator的數(shù)值)敷燎,由于Accumulator存在于Driver端,從節(jié)點(diǎn)讀取不到Accumulator的數(shù)值箩言。
??Spark提供的Accumulator主要用于多個(gè)節(jié)點(diǎn)對(duì)一個(gè)變量進(jìn)行共享性的操作硬贯。Accumulator只提供了累加的功能,但是卻給我們提供了多個(gè)task對(duì)于同一個(gè)變量并行操作的功能陨收,但是task只能對(duì)Accumulator進(jìn)行累加操作饭豹,不能讀取它的值,只有Driver程序可以讀取Accumulator的值务漩。