“夫唯兵者,不祥之器,物或惡之,故有道者不處。
君子居則貴左,用兵則貴右。
兵者不祥之器,非君子之器,不得已而用之,恬淡為上。
勝而不美,而美之者,是樂殺人。
夫樂殺人者,則不可得志于天下矣。
吉事尚左,兇事尚右。
偏將軍居左,上將軍居右,言以喪禮處之。
殺人之眾,以悲哀泣之,戰勝以喪禮處之。”[1]
Spark對RDD的持久化操作(cache()
、persist()
、checkpoint()
)是很重要的,可以將rdd存放在不同的存儲介質中,方便后續的操作能重復使用。
cache()
persist()
cache和persist都是用于將一個RDD進行緩存,這樣在之后使用的過程中就不需要重新計算,可以大大節省程序運行時間。
cache和persist的區別:cache只有一個默認的緩存級別MEMORY_ONLY
,而persist可以根據情況設置其它的緩存級別
。
RDD的緩存級別:
查看 StorageLevel 類的源碼
object StorageLevel {
val NONE = new StorageLevel(false, false, false, false)
val DISK_ONLY = new StorageLevel(true, false, false, false)
val DISK_ONLY_2 = new StorageLevel(true, false, false, false, 2)
val MEMORY_ONLY = new StorageLevel(false, true, false, true)
val MEMORY_ONLY_2 = new StorageLevel(false, true, false, true, 2)
val MEMORY_ONLY_SER = new StorageLevel(false, true, false, false)
val MEMORY_ONLY_SER_2 = new StorageLevel(false, true, false, false, 2)
val MEMORY_AND_DISK = new StorageLevel(true, true, false, true)
val MEMORY_AND_DISK_2 = new StorageLevel(true, true, false, true, 2)
val MEMORY_AND_DISK_SER = new StorageLevel(true, true, false, false)
val MEMORY_AND_DISK_SER_2 = new StorageLevel(true, true, false, false, 2)
val OFF_HEAP = new StorageLevel(false, false, true, false)
......
}
可以看到這里列出了12種緩存級別,但這些有什么區別呢?可以看到每個緩存級別后面都跟了一個StorageLevel的構造函數,里面包含了4個或5個參數,如下:
val MEMORY_ONLY = new StorageLevel(false, true, false, true)
查看其構造函數
class StorageLevel private(
private var _useDisk: Boolean,
private var _useMemory: Boolean,
private var _useOffHeap: Boolean,
private var _deserialized: Boolean,
private var _replication: Int = 1)
extends Externalizable {
......
def useDisk: Boolean = _useDisk
def useMemory: Boolean = _useMemory
def useOffHeap: Boolean = _useOffHeap
def deserialized: Boolean = _deserialized
def replication: Int = _replication
......
}
可以看到StorageLevel類的主構造器包含了5個參數:
- useDisk:使用硬盤(外存)
- useMemory:使用內存
- useOffHeap:使用堆外內存,這是Java虛擬機里面的概念,堆外內存意味著把內存對象分配在Java虛擬機的堆以外的內存,這些內存直接受操作系統管理(而不是虛擬機)。這樣做的結果就是能保持一個較小的堆,以減少垃圾收集對應用的影響。
- deserialized:反序列化,其逆過程序列化(Serialization)是java提供的一種機制,將對象表示成一連串的字節;而反序列化就表示將字節恢復為對象的過程。序列化是對象永久化的一種機制,可以將對象及其屬性保存起來,并能在反序列化后直接恢復這個對象
- replication:備份數(在多個節點上備份)
理解了這5個參數,StorageLevel 的12種緩存級別就不難理解了。
val MEMORY_AND_DISK_SER_2 = new StorageLevel(true, true, false, false, 2) 就表示使用這種緩存級別的RDD將存儲在硬盤
以及內存
中,使用序列化
(在硬盤中),并且在多個節點上備份2
份(正常的RDD只有一份)
checkpoint()
sc.sparkContext.setCheckpointDir('...')
......
......
rdd.cache()
rdd.checkpoint()
......
checkpoint接口是將RDD持久化到HDFS中,與persist的區別是checkpoint會切斷此RDD之前的依賴關系,而persist會保留依賴關系。checkpoint的兩大作用:一是spark程序長期駐留,過長的依賴會占用很多的系統資源,定期checkpoint可以有效的節省資源;二是維護過長的依賴關系可能會出現問題,一旦spark程序運行失敗,RDD的容錯成本會很高。
注意:checkpoint執行前要先進行cache,避免兩次計算。
-
老子《道德經》第三十一章,老子故里,中國鹿邑。 ?