大數(shù)據(jù)技術(shù)學(xué)習(xí)Spark正確的入坑方式-共享變量

在使用spark過程當(dāng)中踩過的一些坑和經(jīng)驗。我們知道Spark是多機(jī)器集群部署的,分為Driver/Master/Worker,Master負(fù)責(zé)資源調(diào)度,Worker是不同的運(yùn)算節(jié)點,由Master統(tǒng)一調(diào)度。

而Driver是我們提交Spark程序的節(jié)點,并且所有的reduce類型的操作都會匯總到Driver節(jié)點進(jìn)行整合。節(jié)點之間會將map/reduce等操作函數(shù)傳遞一個獨(dú)立副本到每一個節(jié)點,這些變量也會復(fù)制到每臺機(jī)器上,而節(jié)點之間的運(yùn)算是相互獨(dú)立的,變量的更新并不會傳遞回Driver程序。

那么有個問題,如果我們想在節(jié)點之間共享一份變量,比如一份公共的配置項,該怎么辦呢?Spark為我們提供了兩種特定的共享變量,來完成節(jié)點間變量的共享。科多大數(shù)據(jù)帶你們來看看spark以及spark streaming中累加器和廣播變量的使用方式,然后重點介紹一下如何更新廣播變量。

累加器

顧名思義,累加器是一種只能通過關(guān)聯(lián)操作進(jìn)行“加”操作的變量,因此它能夠高效的應(yīng)用于并行操作中。它們能夠用來實現(xiàn)counters和sums。Spark原生支持?jǐn)?shù)值類型的累加器,開發(fā)者可以自己添加支持的類型,在2.0.0之前的版本中,通過繼承AccumulatorParam來實現(xiàn),而2.0.0之后的版本需要繼承AccumulatorV2來實現(xiàn)自定義類型的累加器。

如果創(chuàng)建了一個具名的累加器,它可以在spark的UI中顯示。這對于理解運(yùn)行階段(running stages)的過程有很重要的作用。如下圖:

在2.0.0之前版本中,累加器的聲明使用方式如下:

scala> val accum = sc.accumulator(0, "My Accumulator")

accum: spark.Accumulator[Int] = 0

scala> sc.parallelize(Array(1, 2, 3, 4)).foreach(x => accum += x)

...

10/09/29 18:41:08 INFO SparkContext: Tasks finished in 0.317106 s

scala> accum.value

res2: Int = 10

累加器的聲明在2.0.0發(fā)生了變化,到2.1.0也有所變化,具體可以參考官方文檔,我們這里以2.1.0為例將代碼貼一下:

scala> val accum = sc.longAccumulator("My Accumulator")

accum: org.apache.spark.util.LongAccumulator = LongAccumulator(id: 0, name: Some(My Accumulator), value: 0)

scala> sc.parallelize(Array(1, 2, 3, 4)).foreach(x => accum.add(x))

10/09/29 18:41:08 INFO SparkContext: Tasks finished in 0.317106 s

scala> accum.value

res2: Long = 10

廣播變量

累加器比較簡單直觀,如果我們需要在spark中進(jìn)行一些全局統(tǒng)計就可以使用它。但是有時候僅僅一個累加器并不能滿足我們的需求,比如數(shù)據(jù)庫中一份公共配置表格,需要同步給各個節(jié)點進(jìn)行查詢。OK先來簡單介紹下spark中的廣播變量:

廣播變量允許程序員緩存一個只讀的變量在每臺機(jī)器上面,而不是每個任務(wù)保存一份拷貝。例如,利用廣播變量,我們能夠以一種更有效率的方式將一個大數(shù)據(jù)量輸入集合的副本分配給每個節(jié)點。Spark也嘗試著利用有效的廣播算法去分配廣播變量,以減少通信的成本。

一個廣播變量可以通過調(diào)用SparkContext.broadcast(v)方法從一個初始變量v中創(chuàng)建。廣播變量是v的一個包裝變量,它的值可以通過value方法訪問,下面的代碼說明了這個過程:

scala> val broadcastVar = sc.broadcast(Array(1, 2, 3))

broadcastVar: org.apache.spark.broadcast.Broadcast[Array[Int]] = Broadcast(0)

scala> broadcastVar.value

res0: Array[Int] = Array(1, 2, 3)

從上文我們可以看出廣播變量的聲明很簡單,調(diào)用broadcast就能搞定,并且scala中一切可序列化的對象都是可以進(jìn)行廣播的,這就給了我們很大的想象空間,可以利用廣播變量將一些經(jīng)常訪問的大變量進(jìn)行廣播,而不是每個任務(wù)保存一份,這樣可以減少資源上的浪費(fèi)。

更新廣播變量(rebroadcast)

廣播變量可以用來更新一些大的配置變量,比如數(shù)據(jù)庫中的一張表格,那么有這樣一個問題,如果數(shù)據(jù)庫當(dāng)中的配置表格進(jìn)行了更新,我們需要重新廣播變量該怎么做呢。上文對廣播變量的說明中,我們知道廣播變量是只讀的,也就是說廣播出去的變量沒法再修改,那么我們應(yīng)該怎么解決這個問題呢? 答案是利用spark中的unpersist函數(shù)

Spark automatically monitors cache usage on each node and drops out old data partitions in a least-recently-used (LRU) fashion. If you would like to manually remove an RDD instead of waiting for it to fall out of the cache, use the RDD.unpersist() method.

上文是從spark官方文檔摘抄出來的,我們可以看出,正常來說每個節(jié)點的數(shù)據(jù)是不需要我們操心的,spark會自動按照LRU規(guī)則將老數(shù)據(jù)刪除,如果需要手動刪除可以調(diào)用unpersist函數(shù)。

那么更新廣播變量的基本思路:將老的廣播變量刪除(unpersist),然后重新廣播一遍新的廣播變量,為此簡單包裝了一個用于廣播和更新廣播變量的wraper類,如下:

import java.io.{ ObjectInputStream, ObjectOutputStream }

import org.apache.spark.broadcast.Broadcast

import org.apache.spark.streaming.StreamingContext

import scala.reflect.ClassTag

// This wrapper lets us update brodcast variables within DStreams' foreachRDD

// without running into serialization issues

case class BroadcastWrapper[T: ClassTag](

@transient private val ssc: StreamingContext,

@transient private val _v: T) {

@transient private var v = ssc.sparkContext.broadcast(_v)

def update(newValue: T, blocking: Boolean = false): Unit = {

// 刪除RDD是否需要鎖定

v.unpersist(blocking)

v = ssc.sparkContext.broadcast(newValue)

}

def value: T = v.value

private def writeObject(out: ObjectOutputStream): Unit = {

out.writeObject(v)

}

private def readObject(in: ObjectInputStream): Unit = {

v = in.readObject().asInstanceOf[Broadcast[T]]

}

}

利用該wrapper更新廣播變量,大致的處理邏輯如下:

// 定義

val yourBroadcast = BroadcastWrapper[yourType](ssc, yourValue)

yourStream.transform(rdd => {

//定期更新廣播變量

if (System.currentTimeMillis - someTime > Conf.updateFreq) {

yourBroadcast.update(newValue, true)

}

// do something else

})

總結(jié)

spark中的共享變量是我們能夠在全局做出一些操作,比如record總數(shù)的統(tǒng)計更新,一些大變量配置項的廣播等等。而對于廣播變量,我們也可以監(jiān)控數(shù)據(jù)庫中的變化,做到定時的重新廣播新的數(shù)據(jù)表配置情況,另外我使用上述方式,在每天千萬級的數(shù)據(jù)實時流統(tǒng)計中表現(xiàn)穩(wěn)定,所以有相似問題的同學(xué)也可以進(jìn)行嘗試,有任何問題,歡迎隨時騷擾溝通。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內(nèi)容