1.缓存的基本介绍
缓存介绍:
1. 当一个RDD的产生过程(计算过程), 是比较昂贵的(生成RDD整个计算流程比较复杂), 并且这个RDD可能会被多方(RDD会被重复使用)进行使用,
2. 此时为了提升计算效率, 可以将RDD的结果设置为缓存, 这样后续在使用这个RDD的时候, 无需在重新计算了, 直接获取缓存中数据即可.
3. 缓存可以提升Spark的容错的能力, 正常情况, 当Spark中某一个RDD计算失败的时候, 需要对整个RDD链条进行整体的回溯计算.
4. 有了缓存后, 可以将某些阶段的RDD进行缓存操作, 这样当后续的RDD计算失败的时候, 可以从最近的一个缓存中恢复数据 重新计算即可, 无需在回溯所有链条.
应用场景:
1. 当一个RDD被重复使用的时候, 可以使用缓存来解决
2. 当一个RDD产生非常昂贵的时候, 可以将RDD设置为缓存
3. 当需要提升容错能力的时候, 可以在局部设置一些缓存来提升容错能力
注意事项:
1. 缓存仅仅是一种临时存储, 可以将RDD的结果数据存储到内存(executor) 或者 磁盘, 甚至可以存储到堆外内存(executor以外系统内存)中.
2. 由于缓存的存储是一种临时存储, 所以缓存的数据有可能丢失的, 所以缓存操作并不会将RDD之间的依赖关系给截断掉(清除掉),
以防止当缓存数据丢失的时候, 可以让程序进行重新计算操作
3. 缓存的API都是lazy的, 设置缓存后, 并不会立即触发, 如果需要立即触发, 后续必须跟一个action算子, 建议使用 count
如何使用缓存呢?
设置缓存的相关API:
rdd.cache() //执行设置缓存的操作, cache在设置缓存的时候, 仅能将缓存数据放置到内存中
rdd.persist(设置缓存级别) //执行设置缓存的操作, 默认情况下, 将缓存数据放置到内存中, 同时支持设置其他缓存方案
清理缓存的相关API:
1. 默认情况下, 当程序执行完成后, 缓存会被自动清理
2. 如需手动清理缓存, 则写法为: rdd.unpersist() //清理缓存
常用的缓存级别有那些呢?
NONE //表示不缓存
MEMORY_ONLY //仅缓存到内存中,直接将整个对象保存到内存中
MEMORY_ONLY_SER //仅缓存到内存中, 同时在缓存数据的时候, 会对数据进行序列化(从对象 --> 二进制数据)操作, 可以在一定程序上减少内存的使用量
MEMORY_AND_DISK:
MEMORY_AND_DISK_2 //优先将数据保存到内存中, 当内存不足的时候, 可以将数据保存到磁盘中, 带2的表示保存二份
MEMORY_AND_DISK_SER:
MEMORY_AND_DISK_SER_2 //优先将数据保存到内存中, 当内存不足的时候, 可以将数据保存到磁盘中, 带2的表示保存二份,
//对于保存到内存的数据, 会进行序列化的操作, 从而减少内存占用量 提升内存保存数据体量,对磁盘必须要进行序列化
//上述的缓存级别, 带2表示的保存多个副本, 从而提升数据可靠性
序列化解释:
将数据 从 对象 转换为 二进制的数据, 对于RDD的数据来说, 内部数据都是一个个对象,
如果没有序列化是直接将对象存储到内存中, 如果有序列化会将对象转换为二进制然后存储到内存中.
好处:
减少内存的占用量, 从而让有限内存可以存储更多的数据
弊端:
会增大对CPU的占用量, 因为转换的操作, 需要使用CPU来工作
#cache sample.
from pyspark import SparkContext, SparkConf,StorageLevel
import os
import jieba
import time
if __name__ == '__main__':
conf = SparkConf().setMaster('local[*]').setAppName('cache sample')
sc = SparkContext(conf=conf)
rdd_init = sc.textFile('file:///export/data/workspace/cache.sample')
rdd_filter = rdd_init.filter(lambda line: line.strip() != '' and len(line.split()) == 6)
rdd_map = rdd_filter.map(lambda line: (
line.split()[0],
line.split()[1],
line.split()[2][1:-1],
line.split()[3],
line.split()[4],
line.split()[5]
))
# -----------------设置缓存的代码--------------------
# StorageLevel 这个类需要在前面的from pyspark中加入此对象的导入
# 一般建议, 设置完缓存后, 让其立即触发
rdd_map.persist(storageLevel=StorageLevel.MEMORY_AND_DISK).count()
# 快速抽取函数: ctrl + alt + m
xuqiu_1()
# ----------手动清理缓存------------
rdd_map.unpersist().count() //如果这里清理缓存了, 则后续的 xuqiu_2()这个函数, 就用不了缓存了, 可以在DAG图中查看"小绿球"