Spark之RDD持久化、廣播、累加器


        RDD持久化、廣播、累加器實質上分別涉及了RDD的數據如何保存,RDD在構建高效算法的時候涉及了persist或者checkpoint,以及廣播和累加器,通過spark-shell可以試驗一些小功能,spark-shell本身是spark的發行包推出的一個程序,通過這個程序可以直接寫代碼,spark-shell會把代碼直接進行運行。

1.1.   RDD持久化實戰

2個層面考慮持久化:

1)操作RDD的時候怎麼保存結果(屬於Action的部分)

下面使用Spark-shell進行實戰:

1.1.1.  Action級別的操作進行持久化——啓動運行環境

         我們使用基於HadoopHDFS的文件系統,所以只需啓動HadoopHDFS即可:

                             

查看啓動是否成功:


啓動Spark集羣:


 

啓動日誌管理器:


 

啓動spark-shell

構建一個RDD:


1.1.1.1.           reduce

執行一個Action操作:


1.1.1.2.           map


1.1.1.3.           collect

把各個Executor上的結果進行收集後在集羣終端顯示。

我們可以看一下collect的源碼:(RDD.scala 926

/**
 * Return an array that contains all of the elements in this RDD.
 */
def collect(): Array[T] = withScope {
 
val results = sc.runJob(this, (iter: Iterator[T]) => iter.toArray)
  Array.concat(results: _*)
}

collect返回一個Araay,它的工作機制流程圖如下圖:


如果想在命令終端上看到結果必須使用collect

凡是Action級別的操作都會觸發sc.runJob



1.1.1.4.           count



1.1.1.5.           take



1.1.1.6.           countByKey

/**
 * Count the number of elements for each key, collecting the results to a local Map.
 *
 * Note that this method should only be used if the resulting map is expected to be small, as
 * the whole thing is loaded into the driver's memory.
 * To handle very large results, consider using rdd.mapValues(_ => 1L).reduceByKey(_ + _), which
 * returns an RDD[T, Long] instead of a map.
 */
def countByKey(): Map[K, Long] = self.withScope {
  self.mapValues(_ =>
1L).reduceByKey(_ + _).collect().toMap
}

統計每個key出現的次數:




1.1.1.7.           saveAsTextFile


saveAsTextFile可以直接把數據寫到HDFS上。


2)在實現算法的時候要進行cachepersist,另外還有一個是checkpoint

1.1.2.  通過persist進行持久化

         Spark在默認情況下它的數據是放在內存中的,放在內存中適合高速的迭代。在一下情況下需要持久化:

         1)在某步驟計算特別耗時

         2)計算鏈條特別長的情況

         3checkpoint所在的RDD也一定要持久化(在checkpoint之前persist

         4shuffle之後

         5shuffle之前(框架默認幫助我們把數據持久化到本地磁盤),如果shuffle出錯的話,所有的父RDD都要重新計算,代價很大的。

spacer.gif

spacer.gif

如果發現內存經常不夠用或出現OOM的話,一個非常好的方式就是MEMORY中的內容序列化,當然了,在使用數據的時候需要反序列化,反序列話是很消耗CPU的;

下面兩個是優先放到內存,在內存放不下的情況下再放到磁盤:

val MEMORY_AND_DISK = new StorageLevel(true, true, false, true)
val MEMORY_AND_DISK_2 = new StorageLevel(true, true, false, true, 2)

 

spacer.gif

spacer.gif上面這兩個執行時間沒什麼區別,但是如果先cachecount

spacer.gif

spacer.gif執行時間就會提高將近20倍。

由此也得出一個結論:cache後一定不能立即有其它算子!!!

spacer.gif

cache不是一個Action,因爲它並沒有執行一個作業。persistlazy級別的,unpersisteager級別的,cache之後可以使用unpersist清除cachecache只放在內存,而persist可以是內存也可以是磁盤。

1.2.   Spark廣播實戰

         在構建發算法時至關重要,無論是在降低網絡傳輸的數據量、提高內存的使用效率,還是加快程序的運行速度,廣播對於我們而言都是非常重要的。

         爲什麼需要廣播?

         廣播是由Driver發給當前Application分配的所有Executor內存級別的全局制度變量,Executor中的線程池中的線程共享該全局變量,極大地減少了網絡傳輸(否則的話每個Task都要純屬一次該變量)並極大地節省了內存,當然也隱形的提高了CPU的有效工作。

1.3.   Spark累加器實戰

         累加器在Spark集羣中是一個全局的指針步減的變量,且在所有的Executor中只能修改累加器的內容,也就是說只能增加累加器的內容,在Executor中不可以讀累加器的內容,在Driver中可以讀累加器的內容。


備註:

資料來源於:DT_大數據夢工廠(IMF傳奇行動絕密課程)-IMF

更多私密內容,請關注微信公衆號:DT_Spark

如果您對大數據Spark感興趣,可以免費聽由王家林老師每天晚上20:00開設的Spark永久免費公開課,地址YY房間號:68917580

Life is short,you need to Spark.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章