大数据学习之Spark缓存机制

Spark程序中,为完成某些任务,往往经过许多步骤的转换处理,这些操作存在先后顺序和依赖关系(lineage血缘关系)。

对于复杂的任务,某个中间转换结果,可能会被多次调用,而每个中间结果的生成都是经过“千辛万苦”计算得到的。这就意味着,若中间结果A被调用N次,就要求每次调用时,先“千辛万苦”的把A的结果先计算出来,然后再进行调用。

如上图,RDD4作为中间转换结果,经过加载HDFS文件

àfilteràflatMapàmap,最终得到RDD4。RDD4作为中间结果,被后面的三个任务A,B,C分别进行调用。

如何避免”重复劳动”,提高程序运行效率呢?

Spark缓存

基于上述场景,Spark提出了缓存的解决方案。

Spark缓存机制

在应用程序中,若某个中间结果(RDD)被多次调用(触发action),则可以将该中间结果(RDD)缓存起来,第一次调用任务(触发action)时会先进行计算再缓存(首次微慢一些),第二次及后续多次调用该中间结果数据执行任务时,则会直接从缓存中读取进行操作。

这样会带来如下好处:

1:避免重复劳,相同的活只做一次;

2:因为数据在缓存中,所以效率会很高。

Spark缓存级别

生产环境中,根据需要,可以设置不同的缓存级别,如上图,每个缓存级别分析如下:

Øval MEMORY_ONLY = new torageLevel(false, true, false, true)

默认缓存级别,

第一个参数表示 :在内存不足的情况下,是否将未缓存到内存的数据暂时保存到Executor进程所在的机器本地目录(尤其是shuffler后的中间结果,即使保存在磁盘, 也比从HDFS读取要快);

第二个参数表示:是否启用缓存到内存;

第三个参数表示:第三个参数是否生效要参照第一个参数,若第一个参数为false,表示不启用磁盘,这个时候,第三个参数只能是false,设置为true,也没意义;

第四个参数表示:第四个参数是否生效要参照第二个参数,若第二个参数为false,表示不缓存到内存,这个时候,第四个参数只能是false,设置为true,也没意义;就上面MEMOERY_ONLY 来说,第四个参数设置为true,表示缓存到内存的数据是以普通的JAVA对象方式,而非序列化后的对象,所以实际占用内存空间要比源文件大一些。

假如数据很大,内存缓存不下,则会尽可能的缓存到内存,剩余的数据则在每次触发任务时,再临时读取HDFS上的部分数据。

Øval MEMORY_ONLY_SER = new StorageLevel(false, true, false, false)

表示不启用磁盘,只启用将数据缓存到内存(内存的Heap),且缓存到内存的数据先序列化(总的空间变小),注意:第四个参数为:false,表示开启序列化。

Øval MEMORY_AND_DISK_SER_2 = new StorageLevel(true, true, false, false, 2)

表示内存+本地磁盘同时开启(尽可能存内存,内存不足情况下,则将剩下的数据序列化到本地磁盘,有计算时,则先读内存,若没有,则再赵本地磁盘读取),且序列化,且每个缓存的block块数据在本地一份(内存或者磁盘)的同时也同步到其它Worker机器上的相同任务下的内存/磁盘一份作为副本,多用来一定程度上容错。

Ø OFF_HEAP

使用堆外内存,把内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理(而不是虚拟机)。能保持一个较小的堆,减少垃圾收集对应用的影响。

程序中设置缓存设置缓存

通过对重复调用的中间结果(RDD)进行缓存设置,默认方式如下:

rdd3.cache()

根据需要设置其它缓存级别,方式如下

rdd3.persist(缓存级别),如:

rdd3.persist(StorageLevels.MEMORY_AND_DISK)

释放缓存

设置缓存的中间结果(RDD)被调用结束,要进行释放,格式如下: rdd3.unpersist(true)

缓存级别设置的参考依据

Ø 实际加载数据大小

假若中间结果数据不大(相比Executory内存来说),则可以考虑设置MEMORY_ONLY级别;若中间结果数据很大,就不能设置只加内存,否则任务会卡死(数据缓存大,分配给计算的资源就会小),这个时候可以考虑内存+本地磁盘,因为数据在本地,所以也不会太慢。

Ø 分配的Executor-memory大小

Ø 当前worker节点服务器内存使用情况

Ø集群中的worker上资源是否足够大,是否能容得下要被缓存的数据

总结

实际应用中,什么时候需要对数据进行缓存是门艺术,这通常需要对空间和速度进行权衡,垃圾回收开销的问题也会时不时让情况更复杂。一般情况下,如果多个动作需要用到某个中间结果(RDD),而它的计算代价又很高,那么就应该把这个RDD 缓存起来。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190617A05NN700?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券