【博学谷学习记录】超强总结,用心分享|Spark的RDD持久化

RDD的缓存

作用
  1. 通过缓存提升RDD的计算效率,一般当RDD的计算非常耗时,计算规则复杂,或者结果需要被重复使用时,可以将RDD的计算结果缓存起来,便于后续的使用
  2. 通过缓存提升RDD的容错能力,当后续计算失败后,尽量不让RDD回溯所有的依赖链条,从而减少计算时间
注意
  1. 缓存仅仅是一种临时的存储,可能会存在数据丢失, 所以缓存操作, 并不会将RDD之间的依赖关系给截断掉(丢失掉),因为当缓存失效后, 可以基于原有依赖关系重新计算
  2. 缓存数据可以保存到内存(executor内存空间),也可以保存到磁盘中, 甚至支持将缓存数据保存到堆外内存中(executor以外的系统空间)
  3. 缓存的API都是惰性的, 如果需要立即触发缓存操作, 必须后续跟上一个action算子, 一般建议使用count,如果不添加action算子, 只有当后续遇到第一个action算子后, 才会触发缓存
使用

默认情况下, 当整个Spark应用程序执行完成后, 缓存也会自动失效的, 自动删除
常用的缓存级别:

  1. MEMORY_ONLY : 仅缓存到内存中
  2. DISK_ONLY: 仅缓存到磁盘
  3. MEMORY_AND_DISK: 内存 + 磁盘 优先缓存到内存中, 当内存不足的时候, 剩余数据缓存到磁盘
  4. OFF_HEAP: 缓存到堆外内存

最为常用的: MEMORY_AND_DISK

# 执行缓存操作 仅能将数据缓存到内存中
rdd.cache()

# 执行缓存操作, 默认将数据缓存到内存中, 当然也可以自定义缓存位置
rdd.persist(storageLevel=缓存的级别)

# 手动清理缓存的API
rdd.unpersist()

代码演示
import os

from pyspark import SparkContext, SparkConf, StorageLevel

# 锁定远端环境, 确保环境统一
os.environ['SPARK_HOME'] = '/export/server/spark'
os.environ['PYSPARK_PYTHON'] = '/root/anaconda3/bin/python3'
os.environ['PYSPARK_DRIVER_PYTHON'] = '/root/anaconda3/bin/python3'


def xuqiu1():
    rdd_res = rdd_map.map(lambda field_tuple: (field_tuple[2])) \
        .map(lambda keyword: (keyword, 1)) \
        .reduceByKey(lambda agg, curr: agg + curr) \
        .top(10, lambda res_tup: res_tup[1])
    print(rdd_res)


def xuqiu2():
    rdd_res = rdd_map.map(lambda field_tup: ((field_tup[1], field_tup[2]), 1)) \
        .reduceByKey(lambda agg, curr: agg + curr) \
        .top(10, lambda res_tup: res_tup[1])
    print(rdd_res)


if __name__ == '__main__':
    """
    清洗需求: 
        需要先对数据进行清洗转换处理操作, 清洗掉为空的数据, 
        以及数据字段个数不足6个的数据, 并且将每一行的数据放置到一个元组中, 
        元组中每一个元素就是一个字段的数据
    """
    print("Spark的Python模板")
    # 创建核心
    conf = SparkConf().setAppName('测试')
    sc = SparkContext(conf=conf)

    # 读取外部文件
    rdd = sc.textFile(name='file:///export/data/pyprojects/pyspark/data/SogouQ.sample')

    # 执行清洗需求相关操作
    rdd_filter = rdd.filter(lambda line: 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]))

    # 3.1 由于后续rdd_map被多次使用,此时可以将其设置为缓存,使用count动作算子,让缓存操作立即执行
    rdd_map.persist(storageLevel=StorageLevel.MEMORY_AND_DISK).count()

    # 需求一:  统计每个关键词出现了多少次, 获取前10个
    xuqiu1()

    # 3.2 当需求1执行完成, 让缓存失效
    rdd_map.unpersist().count()

    # 需求二:统计每个用户每个搜索词点击的次数
    xuqiu2()

查看DAG图验证缓存是否被使用

代码中步骤3.1设置缓存后,需求1的任务DAG图中,有一个绿色的点,表示缓存点
image.png
代码中步骤3.2让缓存失效后,需求2的任务DAG图中,绿色的缓存点就消失了
image.png

RDD的checkpoint检查点

作用
  1. 提高RDD容错性,基于HDFS存储数据,确保RDD的数据不会丢失
  2. 提高RDD的执行效率,但是由于是基于HDFS存储,性能不如缓存
注意
  1. checkpoint类似于缓存操作,区别在于缓存把数据保存在内存或磁盘中,checkpoint将数据保存在HDFS或磁盘中
  2. checkpoint主要是基于HDFS存储数据,提供了更案例可靠的持久化方案,确保RDD的数据不会发生丢失,所以构建checkpoint后,会将RDD之间的依赖关系截断,后续计算出错时,直接从检查点恢复数据
使用
# 第一步: 设置检查点保存数据位置
    sc.setCheckpointDir('路径地址')

# 第二步: 在对应RDD开启检查点
    rdd.checkpoint()
    rdd.count()

# 注意: 
    如果运行在集群模式中, checkpoint的保存的路径地址必须是HDFS
	如果是local模式 可以支持在本地路径
    checkpoint数据不会自动删除, 必须同时手动方式将其删除掉

代码演示
import time

from pyspark import SparkContext, SparkConf
from pyspark.sql import SparkSession
import os

# 锁定远端环境, 确保环境统一
os.environ['SPARK_HOME'] = '/export/server/spark'
os.environ['PYSPARK_PYTHON'] = '/root/anaconda3/bin/python3'
os.environ['PYSPARK_DRIVER_PYTHON'] = '/root/anaconda3/bin/python3'

if __name__ == '__main__':
    print("演示checkpoint相关的操作")

    # 1- 创建SparkContext对象
    conf = SparkConf().setAppName('checkpoint').setMaster('local[*]')
    sc = SparkContext(conf=conf)

    # 开启检查点, 设置检查点的路径
    sc.setCheckpointDir('/spark/chk') # 默认的地址为HDFS
    # 2- 获取数据集
    rdd = sc.parallelize(['张三 李四 王五 赵六', '田七 周八 李九 老张 老王 老李'])

    # 3- 执行相关的操作:  以下操作仅仅是为了让依赖链条更长, 并没有太多的实际意义
    rdd1 = rdd.flatMap(lambda line: line.split())

    rdd2 = rdd1.map(lambda name: (name, 1))

    rdd3 = rdd2.map(lambda name_tuple: (f'{name_tuple[0]}_itcast', name_tuple[1]))

    rdd3 = rdd3.repartition(3)

    rdd4 = rdd3.map(lambda name_tuple: name_tuple[0])

    # RDD4设置检查点:
    rdd4.checkpoint()
    rdd4.count()


    rdd5 = rdd4.flatMap(lambda name: name.split('_'))
    rdd5 = rdd5.repartition(4)

    rdd6 = rdd5.map(lambda name: (name, 1))

    rdd_res = rdd6.reduceByKey(lambda agg, curr: agg + curr)

    print(rdd_res.collect())

查看DAG图验证checkpoint是否被使用

未使用checkpoint时
image.png
使用checkpoint时
image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值