Spark的cache缓存、存储级别、shuffle弊端与coalesce

本文详细解析了Spark中RDD的缓存(cache)和持久化(persist)机制,探讨了不同存储级别的选择原则及宽窄依赖对执行计划的影响,为优化Spark作业提供了实用指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

官网:http://spark.apache.org/docs/latest/rdd-programming-guide.html#rdd-persistence

Cache

cache(缓存)和persist(持久化)的区别
cache源码里面调用的是persist,persist里面默认存储化级别是内存
cache lazy(spark core里面是lazy的,spark sql在1.x版本默认不是lazy,是eager)

执行的action操作,在cache之后再次执行会缩短时间。Spark每次执行action类型的算子,都会从头重新计算一遍,如果使用了cache或者persist,就可以直接拿存储的结果来用。

val file = sc.textFile("path")
file.cache
file.count

可以在UI界面查看,如果想主动从内存里去掉:(spark会在内存不够的时候自动把最长时间不用的partition的缓存给去掉)

file.unpersist()

存储级别

注意点:
1:内存足够大,MEMORY_ONLY是最好的
2:当内存不够大的时候,MEMORY_ONLY_SER(只存内存并序列化)加上一个快速的序列化框架(比如Kryo)
3:不要把数据写到磁盘,除非重新计算数据集的代价是高昂的,或者溢出到磁盘前已经使用了内存。否则重新计算分区可能和从磁盘上新读取数据的速度一样快
4:启用副本机制,容错会比较高。但是占用空间。

一般存储级别的选择是:
MEMORY_ONLY
MEMORY_AND_DISK
MEMORY_ONLY_SER (Java and Scala)
MEMORY_AND_DISK_SER (Java and Scala)

Shuffle类算子使用的弊端

Lineage 血缘关系/血统

A =map=> B =filter=>C (RDD之间的关系,A通过map得到了B,B通过filter得到了C),这就是血缘关系。
可以知道:一个RDD是如何从父RDD计算过来的 (如果B的某个分区挂了,可以通过A再得到)

Shuffle

shuffle使多个分区(的部分数据)得到一个分区,这样就会有跨执行程序和机器复制数据,使得操作更复杂,而恢复某个挂了的分区也会变复杂(当挂掉的分区是由shuffle得到的)

Denpendence(依赖)
Narrow(窄依赖)  一个父RDD的partition至多被子RDD的某个partition使用一次(join也可以是窄依赖)(一对一或多对一)
Wide(宽依赖) 一个父RDD的partition会被子RDD的某个partition使用多次(一对多或多对多)

窄依赖重新计算会快,宽依赖重新计算会比较慢。
在这里插入图片描述
Wide => Shuffle => 拆成2个stage(一个shuffle拆成两个,两个shuffle拆成三个)
执行一次宽依赖就会把stage拆成两份:
在这里插入图片描述

wordcount使用的依赖(reduceByKey是宽依赖,其余都是窄依赖)
flatMap、map、reduceByKey
在这里插入图片描述

coalesce

可以压缩数量
coalesce(10) => 100 => 10(合并小文件的一种方式)(窄依赖)
对于repartition来说,则是拆分开:
repartition:10==>50 (重新分区)(数据倾斜的一种处理方案)(宽依赖)
一般在filter(filter过滤掉了大量的数据)后加上一个coalesce。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值