spark程序优化之一:善用 persist 方法

场景

在编写spark程序代码的时候,如果涉及大数据运算的时候,一次计算可能得几十分钟甚至一个小时以上,更极端的情况则是,一个较大的对象被多次使用,导致重复计算了很多次。这种做法就会消耗资源,也会浪费我们的时间。那么,针对这种情况,我们有什么方法来避免吗?嗯,很显然是有的,那就是将这个多次计算的对象进行缓存,第一次缓存之后,下次就不使用就可以调用,节省重复计算的时间。当然,这个要分情况,对于计算时间和计算资源消耗较大的时候,这个情况较为符合。如果本身数据量小,计算简单,就没必要。因为保存到缓存的时间比重复计算的时间更长。今天我们就来介绍函数 persist方法

适用场景

  1. spark版本: 1.6以上(不管是版本1.6还是版本2以上,这个函数定义是一致的,只是内部实现存在差异)
  2. 使用spark DataFrame进行运算
  3. 一个对象被多次计算

函数说明

让我们来看看spark1.6里面的persist方法代码:

/**
   * Persist this [[DataFrame]] with the default storage level (`MEMORY_AND_DISK`).
   * @group basic
   * @since 1.3.0
   */
  def persist(): this.type = {
    sqlContext.cacheManager.cacheQuery(this)
    this
  }

  /**
   * Persist this [[DataFrame]] with the default storage level (`MEMORY_AND_DISK`).
   * @group basic
   * @since 1.3.0
   */
  def cache(): this.type = persist()

  /**
   * Persist this [[DataFrame]] with the given storage level.
   * @param newLevel One of: `MEMORY_ONLY`, `MEMORY_AND_DISK`, `MEMORY_ONLY_SER`,
   *                 `MEMORY_AND_DISK_SER`, `DISK_ONLY`, `MEMORY_ONLY_2`,
   *                 `MEMORY_AND_DISK_2`, etc.
   * @group basic
   * @since 1.3.0
   */
  def persist(newLevel: StorageLevel): this.type = {
    sqlContext.cacheManager.cacheQuery(this, None, newLevel)
    this
  }

从上面的代码,可以看到,

  1. 调用cache方法其实就是调用无参的persist
  2. persist()其实相当于persist(StorageLevel.MEMORY_AND_DISK)

其中比较重要的就是StorageLevel对象。这个对象主要是指定我们缓存的级别。那么让我们看看StorageLevel的内部成员:

class StorageLevel private(
    private var _useDisk: Boolean, //是否使用磁盘
    private var _useMemory: Boolean,//是否使用内存
    private var _useOffHeap: Boolean,//是否使用堆外内存
    private var _deserialized: Boolean,//是否反序列化
    private var _replication: Int = 1//备份因子,默认为1)
  extends Externalizable 

那有多少种缓存策略呢,让我们看一下下表:

级别 使用空间 CPU时间 是否在内存中 是否在磁盘上 备注
MEMORY_ONLY
MEMORY_ONLY_2 数据存2份
MEMORY_ONLY_SER 数据序列化
MEMORY_ONLY_SER_2 数据序列化,数据存2份
MEMORY_AND_DISK 中等 部分 部分 如果数据在内存中放不下,则溢写到磁盘
MEMORY_AND_DISK_2 中等 部分 部分 数据存2份
MEMORY_AND_DISK_SER 部分 部分
MEMORY_AND_DISK_SER_2 部分 部分 数据存2份
DISK_ONLY
DISK_ONLY_2 数据存2份
NONE
OFF_HEAP

总结

  1. 一般情况下,建议使用 persist(StorageLevel.MEMORY_AND_DISK)来替代cache()函数,避免因为内存不足而导致出差;
  2. 内存足够的时候,可以直接使用 级别MEMORY_ONLY。因为是直接内存操作,速度很快;
  3. 如果空间不足,可以考虑使用级别MEMORY_ONLY_SER,会节省空间,只是多了一步序列化操作;
  4. 如果第三步还不行,就考虑使用级别MEMORY_AND_DISK,将部分数据存放到磁盘当中;
  5. 除非真的没办法,不然不推荐使用级别DISK_ONLY。存磁盘再读取,会导致性能急剧降低,这个操作可能比重新计算还慢;
  6. 级别后面跟着_2则是代表进行数据备份。如果不是追求作业的高可用行,不推荐使用。
  7. OFF_HEAP,是为了使用JVM堆外内存。使用OFF_HEAP的优势在于,在内存有限时,可以减少频繁的GC及不必要的内存消耗,提升程序性能

你可能感兴趣的:(spark,spark,SQL,总结归纳)