spark作业中,对RDD进行action操作时,会根据血缘关系从头计算。如果RDD被计算多次,建议将RDD进行持久化,确保该RDD本身只被计算一次。
scala> val res = sc.textFile("file:/opt/data/emp.txt").flatMap(_.split("\t")).map((_,1)).reduceByKey(_+_)
res: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[11] at reduceByKey at <console>:24
scala> res.cache
res3: res.type = ShuffledRDD[11] at reduceByKey at <console>:24
打开web ui看看是否缓存成功
发现并没有Storage的记录,因为cache是lazy的,遇上action操作的时候才会真正被缓存起来。这是执行一个action操作,再查看一次。
scala> res.collect
res4: Array[(String, Int)] = Array((1981/6/9,1), (7654,1), (1500.00,1), (1981/9/8,1), (950.00,1), (20,5), (7566,3), (7900,1), (ALLEN,1), (7788,2), (TURNER,1), (1981/9/28,1), (ANALYST,2), (7876,1), ("",11), (1982/1/23,1), (7782,2), (7902,2), (1100.00,1), (JAMES,1), (7698,6), (PRESIDENT,1), (SALESMAN,4), (1250.00,2), (800.00,1), (0.00,1), (WARD,1), (1300.00,1), (ADAMS,1), (500.00,1), (7369,1), (7499,1), (SCOTT,1), (5000.00,1), (1987/4/19,1), (KING,1), (2975.00,1), (SMITH,1), (1400.00,1), (MANAGER,3), (2450.00,1), (3000.00,2), (JONES,1), (2850.00,1), (MILLER,1), (1987/5/23,1), (7934,1), (BLAKE,1), (1980/12/17,1), (1981/5/1,1), (1981/11/17,1), (7844,1), (1981/4/2,1), (30,6), (CLERK,4), (1981/12/3,2), (1981/2/20,1), (1600.00,1), (MARTIN,1), (7521,1), (7839,4), (CLARK,1), (1981/2/22,1), (300....
scala>
![](https://i-blog.csdnimg.cn/blog_migrate/da749bac8e6315a091a0cdbd61570e7d.png)
缓存成功!
持久化级别
持久化级别 | 含义解释 |
---|---|
MEMORY_ONLY | 使用未序列化的Java对象格式,将数据保存在内存中。如果内存不够存放所有的数据,则数据可能就不会进行持久化。那么下次对这个RDD执行算子操作时,那些没有被持久化的数据,需要从源头处重新计算一遍。这是默认的持久化策略,使用cache()方法时,实际就是使用的这种持久化策略。 |
MEMORY_AND_DISK | 使用未序列化的Java对象格式,优先尝试将数据保存在内存中。如果内存不够存放所有的数据,会将数据写入磁盘文件中,下次对这个RDD执行算子时,持久化在磁盘文件中的数据会被读取出来使用。 |
MEMORY_ONLY_SER | 基本含义同MEMORY_ONLY。唯一的区别是,会将RDD中的数据进行序列化,RDD的每个partition会被序列化成一个字节数组。这种方式更加节省内存,从而可以避免持久化的数据占用过多内存导致频繁GC。 |
MEMORY_AND_DISK_SER | 基本含义同MEMORY_AND_DISK。唯一的区别是,会将RDD中的数据进行序列化,RDD的每个partition会被序列化成一个字节数组。这种方式更加节省内存,从而可以避免持久化的数据占用过多内存导致频繁GC。 |
DISK_ONLY | 使用未序列化的Java对象格式,将数据全部写入磁盘文件中。 |
MEMORY_ONLY_2, MEMORY_AND_DISK_2, 等等. | 对于上述任意一种持久化策略,如果加上后缀_2,代表的是将每个持久化的数据,都复制一份副本,并将副本保存到其他节点上。这种基于副本的持久化机制主要用于进行容错。假如某个节点挂掉,节点的内存或磁盘中的持久化数据丢失了,那么后续对RDD计算时还可以使用该数据在其他节点上的副本。如果没有副本的话,就只能将这些数据从源头处重新计算一遍了。 |
持久化选择建议
Spark的存储级别旨在提供内存使用和CPU效率之间的不同折衷。我们建议通过以下流程来选择一个:
如果您的RDD适合默认存储级别(
MEMORY_ONLY
),请将其留在那里。这是CPU处理效率最高的选项,允许RDD上的操作尽可能快地运行。如果没有,请尝试使用
MEMORY_ONLY_SER
并选择快速序列化库,以使对象更加节省空间,但访问速度仍然相当快。(Java和Scala)除非计算数据集的函数很昂贵,否则它们会过滤大量数据,否则不要泄露到磁盘。否则,重新计算分区可能与从磁盘读取分区一样快。
如果要快速恢复故障(例如,如果使用Spark来为Web应用程序提供请求),请使用复制的存储级别。所有的存储级别通过重新计算丢失的数据来提供完全的容错能力,但是复制的容量可让您继续在RDD上运行任务,而无需等待重新计算丢失的分区。
持久化数据删除
Spark会自动监视每个节点上的高速缓存使用情况,并以最近最少使用(LRU)方式删除旧数据分区。如果您想手动删除RDD,而不是等待它退出缓存,请使用该
RDD.unpersist()
方法。