Spark RDD的cache/persist/checkpoint区别

cache方法和persist方法区别:

cache:默认是把数据缓存在内存中,其本质就是调用persist方法;

persist:可以把数据缓存在内存或者是磁盘,有丰富的缓存级别,这些缓存级别都被定义在一个object中,这个object名称为StorageLevel

基于Spark 2.0.2 的源码,可以看到:

/** Persist this RDD with the default storage level (`MEMORY_ONLY`). */
  def cache(): this.type = persist()

说明cache() 调用了persist(),若想知道二者的不同还需要看一下persist函数:

/** Persist this RDD with the default storage level (`MEMORY_ONLY`). */
  def persist(): this.type = persist(StorageLevel.MEMORY_ONLY)

可以看到 persist() 内部调用了persist(StorageLevel.MEMORY_ONLY),继续深入:

/**
   * Mark this RDD for persisting using the specified level.
   *
   * @param newLevel the target storage level
   * @param allowOverride whether to override any existing level with the new one
   */
  private def persist(newLevel: StorageLevel, allowOverride: Boolean): this.type = {
    // TODO: Handle changes of StorageLevel
    if (storageLevel != StorageLevel.NONE && newLevel != storageLevel && !allowOverride) {
      throw new UnsupportedOperationException(
        "Cannot change storage level of an RDD after it was already assigned a level")
    }
    // If this is the first time this RDD is marked for persisting, register it
    // with the SparkContext for cleanups and accounting. Do this only once.
    if (storageLevel == StorageLevel.NONE) {
      sc.cleaner.foreach(_.registerRDDForCleanup(this))
      sc.persistRDD(this)
    }
    storageLevel = newLevel
    this
  }

可以看出来persist有一个StorageLevel类型的参数,这个表示的是RDD的缓存级别

至此便可以得出cache和persist的区别:cache只有一个默认的缓存级别MEMORY_ONLY,而persist可以根据情况设置其它的缓存级别。

RDD的缓存级别

查看StorageLevel类的源码

/**
 * Various [[org.apache.spark.storage.StorageLevel]] defined and utility functions for creating
 * new storage levels.
 */
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(true, true, true, false, 1)

这里可以看到12种缓存级别,但这些有什么区别:每个缓存级别后面都跟了一个StorageLevel的构造函数,里面包含了4个或5个参数,如下:

val DISK_ONLY = new StorageLevel(true, false, false, false)

查看其构造函数:

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 {

  // TODO: Also add fields for caching priority, dataset ID, and flushing.
  private def this(flags: Int, replication: Int) {
    this((flags & 8) != 0, (flags & 4) != 0, (flags & 2) != 0, (flags & 1) != 0, replication)
  }

  def this() = this(false, true, false, false)  // For deserialization

  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:血份数(在多个节点上备份)

val MEMORY_AND_DISK_SER_2 = new StorageLevel(true,true,false,false,2) 就表示使用这种缓存级别的RDD将存储在硬盘以及内存中,使用序列化(在硬盘中),并且在多个节点上备份2份(正常的RDD只有一份)

另外还注意到有一种特殊的缓存级别

val OFF_HEAP = new StorageLevel(true, true, true, false, 1)

使用了堆外内存,StorageLevel 类的源码中有一段代码可以看出这个的特殊性,它不能和其它几个参数共存

if (useOffHeap) {
    require(!deserialized, "Off-heap storage level does not support deserialized storage")
  }

cache/persist/checkpoint区别:

cache和persist可以把数据缓存在内存中或者是本地磁盘,后续需要有一个action去触发缓存的执行

cache:默认是把数据缓存在内存中,后期操作该数据的时候效率比较高。但数据在内存中存储是非常不案例,进程挂掉之后,在内存中的数据也就丢失了。

persist:可以把数据保存在本地磁盘中,后续为了得到该数据需要进行磁盘IO操作,效率比cache低,比cache安全一些。

checkpoint:提供了一个相对而言更加可靠的数据持久化方式,它是把数据持久化保存到分布式文件系统HDFS上,利用DHFS高可靠性、高容错性来最大程序保证数据不丢失。

checkpoint:把数据保存在分布式文件系统中,后续也需要有一个action操作触发checkpoint执行。

这里有一定的区别:cache和persist不会改变RDD的依赖关系(血统),同时也不会开启额外的job来执行cache和persist操作,checkpoint会改变RDD的血统,会开启额外的job来执行checkpoint操作。

猜你喜欢

转载自blog.csdn.net/LINBE_blazers/article/details/86709789