Spark cache的用法及其误区:
一、使用Cache注意下面三点
(1)cache之后一定不能立即有其它算子,不能直接去接算子。因为在实际工作的时候,cache后有算子的话,它每次都会重新触发这个计算过程。
(2)cache不是一个action,运行它的时候没有执行一个作业。
(3)cache缓存如何让它失效:unpersist,它是立即执行的。persist是lazy级别的(没有计算),unpersist时eager级别的。
cache是persist的一种特殊情况
查看源代码RDD.scala
/**
* Set this RDD's storage level topersist its values across operations after the first time
* it is computed. This can only be usedto assign a new storage level if the RDD does not
* have a storage level set yet. Localcheckpointing is an exception.
*/
def persist(newLevel: StorageLevel):this.type={
if(isLocallyCheckpointed){
//This means the user previously called localCheckpoint(), which should havealready
// marked this RDD for persisting.Here we should override the old storage level with
// one that is explicitly requestedby the user (after adapting it to use disk).
persist(LocalRDDCheckpointData.transformStorageLevel(newLevel),allowOverride =true)
} else{
persist(newLevel,allowOverride =false)
}
}
/** Persist this RDD with the default storage level (`MEMORY_ONLY`). */
def persist():this.type= persist(StorageLevel.MEMORY_ONLY)
/** Persist this RDD with the default storage level (`MEMORY_ONLY`). */
def cache():this.type= persist()
二、spark常见存储级别简单说明:
MEMORY_AND_DISK:spark优先考虑内存,如果内存足够的话就放在内存中,如果内存不够用的话,就把数据放在磁盘。
MEMORY_AND_DISK和MEMORY有什么区别呢?两个都优先考虑内存,但是MEMORY必须是内存,MEMORY的角度如果内存不够用的话就出现OOM,或数据会丢失。但是MEMORY_AND_DISK会把数据存在磁盘,不会出现数据丢失,主要会防止OOM,它会极大的降低OOM的可能,但是不管用什么方式都有可能出现OOM。
MEMORY_ONLY_SER_2,因为在内存中会有两个副本,如果其中一份内存崩溃就可以立即切换到另一份副本进行快速的计算,这就极大提升了计算,用空间换时间。
三、通过实例观察cache:
没有进行cache时耗时:
-
17/01/21 14:02:04 INFOscheduler.DAGScheduler: Job 7 finished: count at <console>:28, took4.480135 s
-
res10: Long = 33254
-
scala>sc.textFile("/data/5000-8.txt.1").flatMap(_.split("")).map(word => (word, 1)).reduceByKey(_+_, 1).count
(1)加了一个cache,第一次执行
-
17/01/21 14:03:48 INFOscheduler.DAGScheduler: Job 9 finished: count at <console>:28, took 4.617932s
-
res12: Long = 33254
-
scala>sc.textFile("/data/5000-8.txt.1").flatMap(_.split("")).map(word => (word, 1)).reduceByKey(_+_, 1).cache.count
(2)加了一个cache,第二次执行
-
17/01/21 14:04:49 INFOscheduler.DAGScheduler: Job 11 finished: count at <console>:28, took 0.462498s
-
res14: Long = 33254
-
scala>sc.textFile("/data/5000-8.txt.1").flatMap(_.split("")).map(word => (word, 1)).reduceByKey(_+_, 1).cache.count
(3)当赋值后再次进行:速度提升了二十倍不止:
-
val cached =sc.textFile("/data/5000-8.txt.1").flatMap(_.split("")).map(word => (word, 1)).reduceByKey(_+_, 1).cache
-
17/01/21 14:08:00 INFOscheduler.DAGScheduler: Job 14 finished: count at <console>:30, took0.079047 s
-
res17: Long = 33254
-
scala> cached.count
cache放在内存中只有一份副本,只放在内存中,放在内存的Heap中。不会保存在什么目录或者HDFS上,有可能在很多机器的内存,数据量比较小,也有可能在一台机器的内存中。
四、Persist使用场合
1,某步骤计算特别耗时;
2,计算链条特别长;
3,checkpoint所在的RDD也一定要persist(在checkpoint之前,手动进行persist)持久化数据,为什么?checkpoint的工作机制,是lazy级别的,在触发一个作业的时候,开始计算job,job算完之后,转过来spark的调度框架发现RDD有checkpoint标记,转过来框架本身又基于这个checkpoint再提交一个作业,checkpoint会触发一个新的作业,如果不进行持久化,进行checkpoint的时候会重算,如果第一次计算的时候就进行了persist,那么进行checkpoint的时候速度会非常的快。
4,shuffle之后;
5,shuffle之前(框架默认帮助我们数据持久化到本地磁盘)
persist内存不够用时数据保存在磁盘的哪里???
Executor local directory,executor运行的时候,有一个local direcory(本地目录,这是可以配置的)
cache通过unpersit强制把数据从内存中清除掉,如果计算的时候,肯定会先考虑计算需要的内存,这个时候,cache的数据就与可能丢失。
问题:cache本身不能指定机器做缓存,这个是框架帮你做的;
序列化一般使用kryo序列化器
2份副本不会同时读数据,实际上只读一份,另一份是备胎。
如果数据缓存到一台机器上,如果数据量比较小的话,就放在本地执行计算,如果数据量比较大的话,不幸数据被放在一台机器上了,它会先排队,宁愿等一会儿,如果不行了,就从其它机器上抓取缓存。一般情况下是不会跨越机器
MapReduce过程详解及其性能优化请查看http://blog.csdn.net/aijiudu/article/details/72353510