问题描述
最近在pyspark处理90多G数据的时候,遇到这个问题,特此记录,希望能够帮到你
首先你可能会有以下错误或警告:
Lost executor 2 on bjxg-bd-slave65: Container killed by YARN for exceeding memory limits.
60.1 GB of 55 GB physical memory used. Consider boosting spark.yarn.executor.memoryOverhead
or disabling yarn.nodemanager.vmem-check-enabled because of YARN-4714
或者在执行行动算子的时候遇到这种问题:
在web UI你会看到,stage里有好多failed
解决办法
1. 确保不是数据倾斜
如果你用了groupby这样的分组聚合操作,数据量大了之后可能就会发生数据倾斜,导致某几个task的数据量特别大,超出分配的内存被kill,像这种情况只能是优化算子,比如两端聚合的方式解决,具体看:
https://blog.csdn.net/qq_42363032/article/details/119824492
2. 利用cache,算子调优
- 其次要确保你的惰性算子没有被重复的执行,利用cache或者persist,在行动算子之前进行缓存,当然也可以设置存储级别,详细的可自行百度
- 关于spark算子调优也是一堆,我只说我解决这个错误所用到的:
- 1.广播大变量broadcast,用完之后记得手动GC unpersist
- 2.尽量少用count、collect这种拉取到driver端的行动算子,可以在它俩之前加cache,用后upersist。为什么要之前加cache?因为spark惰性计算。
- 3.尽量避免大表join小表的shuffle操作,如果实在避免不了可以利用广播,这个也是一百度一大堆
- 4.在处理的时候,能通过select或filter减少shuffle的数据一定要提前减少,降低处理时内存占用和通信时间
- 5.确保你处理的数据是没有null的,我试过,如果有null的话,明显要比没有null的快,就算你填个空串也比null强
3. 资源调优
大家可以百度到,这种报错,很多都说加executor memory和executor memoryOverhead,加这个是没错,但是要确保你的整个处理流程,算子是想不到哪里还可以优化了,然后再加资源,这才是正确的调优逻辑。先分享我的资源:
ss = SparkSession(sc).builder \
.config('spark.sql.shuffle.partitions', 3000) \
.config('spark.driver.memoryOverhead', '30g') \
.config('spark.driver.maxResultSize', '30g') \
.config('spark.executor.memoryOverhead', '40g') \
.config('spark.shuffle.io.maxRetries', 10) \
.config('spark.shuffle.io.retryWait', 10) \
.config('spark.default.parallelism', 30) \
.config('spark.kryoserializer.buffer.max', 5120) \
.config('spark.dynamicAllocation.enabled', 'true') \
.config("spark.sql.execution.arrow.enabled", "true")\
.config("spark.memory.fraction", 0.2)\
.config('spark.sql.caseSensitive', 'true') \
.getOrCreate()
PYSPARK_PYTHON=/data/anaconda3/bin/python3 \
/opt/spark/bin/spark-submit \
--master yarn \
--deploy-mode client \
--driver-memory 30g \
--driver-cores 4 \
--executor-memory 50g \
--num-executors 6 \
--executor-cores 5 \
driver-memory
、driver-cores
:字面意思driver的内存和核数,这个根据数据量和处理复杂度进行设置executor-memory
、num-executors
、executor-cores
:分别为executor的内存、数量、核数,也是根据要处理的数据量和复杂度进行设置,我这两相当于给了50 * 6的内存,6*5的核数相当于我rdd并行度最高是30,记得看到过一篇文章说executor-cores最好不要超过6,最好的是num-executors多一点spark.sql.shuffle.partitions
:spark sql的并行度,对于大数据来说高点还是有用的,能够轻微的防止数据倾斜,但是小数据的并行度尽量别太高,要不然跑的太慢,默认是200spark.driver.memoryOverhead
:driver的堆外内存spark.driver.maxResultSize
:它是所有分区序列化结果大小的总和,它不能大于你的executor-memory,在范围内增大可以防止内存不足spark.executor.memoryOverhead
:executor的堆外内存,我理解的它是executor所需的额外内存开销spark.default.parallelism
:rdd的并行度,它是你executor数量和核数的乘数,比如我这就是5*10spark.memory.fraction
:这个值一定要调,它默认是0.6,也就是40%的空间保留你的数据结构,元数据等,调到0.2,说明你有80%的空间保留你的这些数据。它可以在你cache的时候,先在磁盘,在再内存,相当于减少了缓存时用的内存。
如果帮到你,请你点赞支持