spark中cache()、persist()、checkpoint()解析

“夫唯兵者,不祥之器,物或惡之,故有道者不處。
君子居則貴左,用兵則貴右。
兵者不祥之器,非君子之器,不得已而用之,恬淡為上。
勝而不美,而美之者,是樂殺人。
夫樂殺人者,則不可得志于天下矣。
吉事尚左,兇事尚右。
偏將軍居左,上將軍居右,言以喪禮處之。
殺人之眾,以悲哀泣之,戰勝以喪禮處之。”[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,避免兩次計算。


  1. 老子《道德經》第三十一章,老子故里,中國鹿邑。 ?

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容