Spark RDD cache persist checkpoint用法及区别

cache/persist 持久化

cache

  • 设置RDD缓存级别为 只在内存中 存储;其实内部调用的就是persist()方法
    在这里插入图片描述

persist

  • 可以灵活的设置RDD缓存级别(方式); 具体pyspark中如下;具体选用哪种,基本优缺点 和 内存/磁盘 的一样;根据情况选择
from pyspark import StorageLevel
StorageLevel.DISK_ONLY  # 存储方式:磁盘; 存储份数:1份; 存储格式:序列化的Java对象
StorageLevel.DISK_ONLY_2  # 存储方式:磁盘; 存储份数:2份; 存储格式:序列化的Java对象
StorageLevel.DISK_ONLY_3  # 存储方式:磁盘; 存储份数:3份; 存储格式:序列化的Java对象
StorageLevel.MEMORY_ONLY  # 存储方式:内存; 存储份数:1份; 存储格式:序列化的Java对象
StorageLevel.MEMORY_ONLY_2  # 存储方式:内存; 存储份数:2份; 存储格式:序列化的Java对象
StorageLevel.MEMORY_AND_DISK  # 存储方式:优先内存,不够时存磁盘; 存储份数:1份; 存储格式:序列化的Java对象
StorageLevel.MEMORY_AND_DISK_2  # 存储方式:优先内存,不够时存磁盘; 存储份数:2份; 存储格式:序列化的Java对象
StorageLevel.OFF_HEAP  # 存储方式:优先内存,不够时存磁盘; 存储份数:1份; 存储格式:序列化的Java对象,使用堆外内存;
StorageLevel.MEMORY_AND_DISK_DESER  # 存储方式:优先内存,不够时存磁盘; 存储份数:1份; 存储格式:未序列化的Java对象

相关连接:pysaprk-StorageLevel()

持久化特点(cache/persist)

  • 当缓存执行时,会在血缘关系中添加 CachedPartitions的依赖; 这样,当子RDD出现问题时,可以通过血缘关系从 缓存中读取数据,不用再重头计算;
    在这里插入图片描述
  • 由于是缓存在内存中,可能出现当内存不足时,删除缓存数据,导致此缓存失效的情况,这时就要通过血缘关系 重新计算; 这也是cache的的缺点:缓存不可靠; 即使是使用persist()方法 缓存到磁盘,当遇到Executor所在机器突然宕机,仍然需要重新计算;
  • 持久化是在Executor端执行; 在2个job需要公用同一个RDD时,可以使用cache操作,将此RDD数据缓存,这样一个job执行完毕后,另一个job可以直接读取此RDD缓存数据; 所以cache生命周期不是job级别,而应该是Application级别;
  • 触发 持久化操作 是在 RDD的算子方法 运行时(算子操作时,RDD才会真正运行,才会有数据进行缓存),也就是对应的job先执行完毕,后续的job才能利用到缓存;

示例代码

# -*- coding: utf-8 -*-
"""
(C) rgc
All rights reserved
create time '2021/5/30 20:06'

Usage:
"""
# 构建spark
from pyspark import StorageLevel
from pyspark.conf import SparkConf
from pyspark.context import SparkContext

conf = SparkConf()
# 使用本地模式;且 executor设置为1个方便debug
conf.setMaster('local[1]').setAppName('rgc')
sc = SparkContext(conf=conf)

rdd = sc.parallelize([2, 1], 1)


def map_func(x: int) -> tuple:
    """
    将每个元素转为元祖
    :param x: rdd中每个元素
    :return:
    """
    print(f'计算map_func:{x}')
    return (x, 1)


def map_func1(x):
    print(f'第二个map func:{x}')
    return x


# 设置检查点存储数据的文件夹路径
sc.setCheckpointDir('/Users/rgc/project/mulit/spark_use/checkpoint')

map_rdd = rdd.map(map_func)
print('初始', str(map_rdd.toDebugString(), 'utf8'))
# 持久化存储
# Application执行完毕,则缓存的数据便会丢弃;也就是 缓存的生命周期为Application执行期间
# 当缓存执行时,会在血缘关系中添加 CachedPartitions的依赖; 这样,当子RDD出现问题时,可以通过血缘关系从 缓存中读取数据,不用再重头计算;
# cache:设置RDD缓存级别为 只在内存中存储;其实内部调用的就是persist()方法
# map_rdd = map_rdd.cache()
# persist:可以灵活设置RDD缓存级别 可以存在内存/硬盘等等;
map_rdd = map_rdd.persist(StorageLevel.DISK_ONLY)
map_rdd = map_rdd.map(map_func1)
print(map_rdd.collect())
print('加缓存结果', str(map_rdd.toDebugString(), 'utf8'))

checkpoint(检查点)

  • 通过在RDD之间设置检查点,并将检查点之前的RDD相关数据存入到HDFS等高可靠文件系统中;从而保证在出现问题时,通过 血缘关系,找到检查点对应的数据,这样就不用从头开始计算RDD;实现了 高容错性,也节约了资源;
  • 由于数据保存在HDFS等文件系统中,保证了数据的可靠存储,这时检查点之前的血缘关系就不再需要,因此 会斩断 检查点之前的血缘关系;
  • 执行检查点时,会重新生成一个job;这个job会重头开始执行直到检查点之前的RDD为止;这样会造成检查点之前的RDD被重复执行2遍; 这时可以结合 持久化(cache/persist)方法 缓存检查点之前的RDD,从而节约资源;
  • 检查点的数据在程序结束后 仍然保存在HDFS或者普通文件系统中; 也就是 数据持久性保存;

示例代码

# -*- coding: utf-8 -*-
"""
(C) rgc
All rights reserved
create time '2021/5/30 20:06'

Usage:
"""
# 构建spark
from pyspark import StorageLevel
from pyspark.conf import SparkConf
from pyspark.context import SparkContext

conf = SparkConf()
# 使用本地模式;且 executor设置为1个方便debug
conf.setMaster('local[1]').setAppName('rgc')
sc = SparkContext(conf=conf)

rdd = sc.parallelize([2, 1], 1)


def map_func(x: int) -> tuple:
    """
    将每个元素转为元祖
    :param x: rdd中每个元素
    :return:
    """
    print(f'计算map_func:{x}')
    return (x, 1)


def map_func1(x):
    print(f'第二个map func:{x}')
    return x


# 设置检查点存储数据的文件夹路径
sc.setCheckpointDir('/Users/rgc/project/mulit/spark_use/checkpoint')

# map操作
map_rdd = rdd.map(map_func)

# checkpoint(检查点):在RDD之间设置检查点,这样 检查点之前的所有RDD计算结果都以文件的方式保存在hdfs等这种高可靠的文件系统中;
# 由于保存结果文件的高可靠性,所以 检查点之前 RDD之间的血缘关系 可以丢弃或斩断; 这样后续计算如果出现问题,则直接从检查点获取结果;
# 检查点 会形成新的job 从新计算一次;所以可以添加缓存,减少重复计算;
# 检查点比缓存 存储的高可靠;如果缓存丢失,则需要从头计算;
map_rdd = map_rdd.persist(StorageLevel.DISK_ONLY)
print('加缓存', str(map_rdd.toDebugString(), 'utf8'))
map_rdd.checkpoint()

map_rdd = map_rdd.map(map_func1)
print(map_rdd.collect())

print('后续\n', str(map_rdd.toDebugString(), 'utf8'))

结果分析

  • 示例代码中只有一个行动算子collect(),然而有2个jobs;所以一个是collect()生成的job;另一个是 checkpoint生成的job;
    在这里插入图片描述
  • 示例代码中 由于在检查点之前添加了 缓存功能;所以代码中的 map_func函数只会执行一次;

何时使用

  • 当血缘关系 过长时,如果重新计算 资源及时间耗费过大,可以使用检查点
  • 当 计算耗费资源过大时,如 宽依赖时 可以使用检查点

持久化(cache/persist)和checkpoint比较

  • 可靠性:持久化由于数据只能保存在Executor所在机器的内存或者磁盘上;这种方式无法保证数据的可靠性;当机器宕机时,那么持久化也就失效了;需要根据血缘关系重新计算RDD; 而 checkpoint由于数据保存在HDFS等文件系统中,保证了数据的可靠性;
  • 数据持久性: 持久化(cache/persist)的数据生命周期为Application;而 checkpoint的数据生命周期是永久存在,即使程序结束;
  • 血缘关系: 持久化(cache/persist)只能添加一个 缓存标识的依赖;而 checkpoint会 斩断血缘关系,使 血缘关系从 checkpoint开始;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值