Spark_03 RDD专题_02

说明

本章主要继续对RDD进行介绍,主要内容有缓存机制,checkpoint机制,spark的运行流程,spark的shuffle过程,spark并行度等部分。

RDD的缓存和checkpoint机制

明确:缓存和checkpoint的作用都是在计算过程中增加容错率,减少时间成本,提高工作效率。

解释:rdd在计算时会有多个依赖,为了避免计算错误时从头开始计算,可以将中间依赖进行缓存或checkpoint,缓存或checkpoint也叫作rdd的持久化 ,一般对某个计算特别复杂的rdd进行持久化 。

缓存

缓存是将数据存储在内存或者磁盘上,计算结束后缓存自动清空

缓存级别

概念:指定缓存的数据位置,默认是缓存到内存上。

StorageLevel.DISK_ONLY # 将数据缓存到磁盘上
StorageLevel.DISK_ONLY_2 # 将数据缓存到磁盘上 保存两份
StorageLevel.DISK_ONLY_3 # 将数据缓存到磁盘上 保存三份
StorageLevel.MEMORY_ONLY # 将数据缓存到内存  默认
StorageLevel.MEMORY_ONLY_2 # 将数据缓存到内存 保存两份
StorageLevel.MEMORY_AND_DISK # 将数据缓存到内存和磁盘  优先将数据缓存到内存上,内存不足可以缓存到磁盘
StorageLevel.MEMORY_AND_DISK_2  # 将数据缓存到内存和磁盘
StorageLevel.OFF_HEAP # 基本不使用 缓存在系统管理的内存上 jvm(内存)在系统上运行,系统内存
StorageLevel.MEMORY_AND_DISK_ESER # 将数据缓存到内存和磁盘  序列化操作,按照二进制存储,节省空间

缓存的使用

from pyspark import SparkContext

#导入缓存级别
from pyspark.storagelevel import StorageLevel
sc = SparkContext(appName='cache')

#获取文件数据转化为rdd
rdd = sc.textFile('hdfs://node1:8020/data/words.txt')
# 对字符串数据先进行切割
rdd_split = rdd.flatMap(lambda x: x.split(','))
# 将数据转化为k-v结构
rdd_kv = rdd_split.map(lambda x: (x, 1))
# 对kv数据分组后累加计算
rdd_reduce = rdd_kv.reduceByKey(lambda a, b: a + b)

# 分组计算进行缓存
# 默认级别设置  storageLevel=StorageLevel.MEMORY_ONLY
rdd_reduce.persist(storageLevel=StorageLevel.MEMORY_ONLY_2)

# 排序
rdd_sort = rdd_reduce.sortBy(lambda x: x[1], ascending=False)

# 查看数据
# 数据缓存需要使用action算子触发
res = rdd_sort.collect()
print(res)


# 后面使用rdd_reduce时,会从缓存处获取数据处理
rdd_sort2 = rdd_reduce.sortBy(lambda x:x[1])
res = rdd_sort2.collect()
print(res)


# 释放缓存,手动释放(了解)
# 实际开发中不需要手动释放,程序结束会自动是释放
rdd_reduce.unpersist()


rdd_sort3 = rdd_reduce.sortBy(lambda x:x[1])
res = rdd_sort3.collect()
print(res)

Checkpoint

将中间rdd数据存储起来,但是存储的位置是在分布式存储系统,可以进行永久保存,程序结束不会释放。如果需要删除就在hdfs上删除对应的目录文件。

checkpoint的使用

from pyspark import SparkContext

sc = SparkContext(appName='checkpoint')
# todo:指定checkpoint保存的路径
sc.setCheckpointDir('hdfs://node1:8020/checkpointdata')

# 获取文件数据转化rdd
rdd = sc.textFile('hdfs://node1:8020/data/words.txt')
# 对字符串数据先进行切割
rdd_split = rdd.flatMap(lambda x: x.split(','))
# 将数据转化为kv结构
rdd_kv = rdd_split.map(lambda x: (x, 1))
# 对kv数据分组后累加计算
rdd_reduce = rdd_kv.reduceByKey(lambda a, b: a + b)

# todo:分组计算的结果进行checkpoint
rdd_reduce.checkpoint()

# 排序
rdd_sort = rdd_reduce.sortBy(lambda x: x[1], ascending=False)

# 查看数据
# 数据checkpoint需要使用action算子触发
res = rdd_sort.collect()
print(res)


# 后面的rdd_reduce时,会从checkpoint处获取数据处理
rdd_sort2  = rdd_reduce.sortBy(lambda x:x[1])
res = rdd_sort2.collect()
print(res)

缓存和checkpoint的区别

生命周期:缓存在程序结束后自动删除,checkpoint程序结束后仍然保存在hdfs上

存储位置:缓存优先存储在内存上,也可以选择存储在本地磁盘上

                  checkpoint存储在hdfs上

依赖:缓存数据后会保留依赖,是临时存储,数据可能会丢失,所以需要保留依赖,当缓存丢失后可以重新计算。

checkpoint数据后会断开依赖,数据保存在hdfs,hdfs副本机制可以保证数据不丢失,所以没有必要保留依赖关系。

RDD的依赖

概念:新的rdd是由旧的rdd计算或转化得带的

窄依赖:父RDD和子RDD的分区是一对一的,触发窄依赖的一般都是transformation算子如map,flatmap,fliter等。

宽依赖:父RDD和子RDD的分区是一对多的,触发宽依赖的一般都是action算子如reduce,sortBy等。

DAG

用于管理依赖关系,是有向无环图(一种图算法)。

作用

管理rdd依赖关系,保证rdd按照依赖关系进行数据的顺序计算。会根据rdd的依赖关系把计算过程部分成多个计算步骤,每个计算步骤成为一个stage。在计算的rdd依赖关系中,一旦发生了宽依赖,就会进行步骤拆分, 生成新的stage。

为什么要划分stage

不同stage中的task可以并行计算, 互不影响

设有一个rdd1属于stage1, rdd1和rdd2存在宽依赖关系, 此时不能并行执行, rdd1分区数据是两个task共同计算的结果(线程同时计算会有抢占资源, 造成计算不准确)

Spark的运行流程(内核调度)

  1. 构建Spark Application的运行环境:启动SparkContext,它是Spark应用程序的入口点,负责与资源管理器(如Standalone、Mesos或YARN)通信,申请资源并建立执行Executor。

  2. 资源管理器分配Executor资源:资源管理器根据资源申请要求和Worker节点的心跳信息,决定在哪个Worker节点上分配资源,并启动StandaloneExecutorBackend

  3. 构建DAG图SparkContext构建有向无环图(DAG),将DAG分解成多个阶段(Stage),并将任务集(TaskSet)发送给任务调度器(Task Scheduler。

  4. 任务调度Task Scheduler负责将任务分配给Executor执行。它将任务集发放给Executor,同时SparkContext将应用程序代码发放给Executor。

  5. Executor执行任务:Executor接收任务并在其上运行,执行完毕后释放所有资源。

  6. 任务结果反馈:执行结果将反馈给Task Scheduler,然后再反馈给DAG Scheduler

  7. 作业完成和资源释放:当所有任务执行完毕后,SparkContext向资源管理器注销并释放所有资源。

  8. 数据本地性和推测执行优化:Spark的优化机制包括数据本地性优化,即尽可能在数据所在的位置执行任务,以及推测执行,用于处理任务执行慢或失败的情况。

  9. 运行模式:Spark支持多种运行模式,包括本地模式、伪分布式模式以及与多种资源管理器(如Standalone、YARN、Mesos)集成的分布式模式。

Spark的shuffle流程

作用:将rdd的数据传递给下一个rdd,进行数据交换。

本质:数据交换

应用场景:当执行宽依赖的算子就会进行shuffle

有俩个部分组成,写map阶段,将上一个stage的计算结果写入,读reduce阶段,拉取上一个stage和当前stage进行合并。

spark的shuffle方法类:

hashshuffle:进行的是hash计算 。

sortshuffle:进行的是排序计算

SparkShuffle配置:

spark.shuffle.file.buffer

该参数用于设置shuffle write task的BufferedOutputStream的buffer缓冲大小(默认是32K)。将数据写到磁盘文件之前会先写入buffer缓冲中,待缓冲写满之后,才会溢写到磁盘。

调优建议:如果作业可用的内存资源较为充足的话,可以适当增加这个参数的大小(比如64k),从而减少shuffle write过程中溢写磁盘文件的次数,也就可以减少磁盘IO次数,进而提升性能。在实践中发现,合理调节该参数,性能会有1%~5%的提升

spark.reducer.maxSizeInFlight

该参数用于设置shuffle read task的buffer缓冲大小,而这个buffer缓冲决定了每次能够拉取多少数据。(默认48M)

调优建议:如果作业可用的内存资源较为充足的话,可以适当增加这个参数的大小(比如96m),从而减少拉取数据的次数,也就可以减少网络传输的次数,进而提升性能。在实践中发现,合理调节该参数,性能会有1%~5%的提升。

spark.shuffle.io.maxRetries and spark.shuffle.io.retryWait

shuffle read task从shuffle write task所在节点拉取属于自己的数据时,如果因为网络异常导致拉取失败,是会自动进行重试的。该参数就代表了可以重试的最大次数。(默认是3次)spark.shuffle.io.retryWait:该参数代表了每次重试拉取数据的等待间隔。

调优建议:一般的调优都是将重试次数调高,不调整时间间隔。

spark.shuffle.memoryFraction=10

该参数代表了Executor 1G内存中,分配给shuffle read task进行聚合操作内存比例。

spark.shuffle.sort.bypassMergeThreshold=200

  • 根据task数量决定sortshuffle的模式

  • task数量小于等于200 就采用bypass task大于200就采用普通模式

当ShuffleManager为SortShuffleManager时,如果shuffle read task的数量小于这个阈值(默认是200),则shuffle write过程中不会进行排序操作。 调优建议:当你使用SortShuffleManager时,如果的确不需要排序操作,那么建议将这个参数调大一些

Spark并行度

分为资源并行度和数据并行度。调整并行度,提高运行效率,合理分配资源

资源并行度

又称为物理并行,由executors节点数和cores核数决定。

定义:task在执行任务时能够使用到的cpu核心数量多任务,多个进程或多个线程执行任务

两种方式:并行 (多个任务同时执行) 并发 (多个任务交替执行)

spark中cpu核心数据设置:

--num-executors=2 设置executors数量

--executor-cores=2 设置每个executors中的cpu核心数,不能超过服务器cpu核心数

数据并行度

又称为逻辑并行,由task数量决定,task由分区数决定。

说明

为了保证task能充分利用cpu资源,实现并行计算,需要设置的task数量应该和资源并行度(cpu核心数)一致。task = cpu core 这样会导致计算快的task执行结束后,一些资源就会处于等待状态,浪费资源

在实际公司中就要根据公司资源并行度设置分区数。建议task数量是cpu core的2~3倍,只有task足够多才能更好的利用资源,但是如果task很多的话,资源少,那么就会先执行一批后再执行下一批。

并行度设置

资源并行度设置

交互模式设置

pyspark --master yarn --num-executors=3  --executor-cores=2

开发模式设置

spark-submit --master yarn --num-executors=3 --executor-cores=2  /root/python_spark/a.py

数据并行度设置

创建rdd对象时指定分区数

sc.parallelize(c=, numSlices=)
sc.textFile(name=, minPartitons=)
sc.wholeTextFiles(name=, minPartitons=)

调用rdd对象transformation算子时修改分区数

rdd.distinct(numPartitions=)
rdd.groupBy(numPartitions=)

调用rdd对象修改分区数的transformation算子

rdd/df.repartition(numPartitions=)
rdd/df.coalesce(numPartitions=,shuffle=False)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值