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級別的操作進行持久化——啓動運行環境
我們使用基於Hadoop的HDFS的文件系統,所以只需啓動Hadoop的HDFS即可:
查看啓動是否成功:
啓動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)在實現算法的時候要進行cache、persist,另外還有一個是checkpoint
1.1.2. 通過persist進行持久化
Spark在默認情況下它的數據是放在內存中的,放在內存中適合高速的迭代。在一下情況下需要持久化:
1)在某步驟計算特別耗時
2)計算鏈條特別長的情況
3)checkpoint所在的RDD也一定要持久化(在checkpoint之前persist)
4)shuffle之後
5)shuffle之前(框架默認幫助我們把數據持久化到本地磁盤),如果shuffle出錯的話,所有的父RDD都要重新計算,代價很大的。
如果發現內存經常不夠用或出現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)
上面這兩個執行時間沒什麼區別,但是如果先cache再count
執行時間就會提高將近20倍。
由此也得出一個結論:cache後一定不能立即有其它算子!!!
cache不是一個Action,因爲它並沒有執行一個作業。persist是lazy級別的,unpersist是eager級別的,cache之後可以使用unpersist清除cache。cache只放在內存,而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.