Spark 中OOM的现象、原因、解决方案和总结

出现OMM的现象

参考:https://blog.csdn.net/zhuiqiuuuu/article/details/86539385
出现这种情况的大约有两个情况:
1、map执行内存溢出
2、shuffle后内存溢出
map执行中内存溢出代表了所有map类型的操作。包括:flatMap,filter,mapPatitions等。
shuffle后内存溢出的shuffle操作包括join,reduceByKey,repartition等操作。

spark中的内存

参考:https://www.cnblogs.com/frankdeng/p/9301783.html
spark的Executor的Container内存有两大部分组成:堆外内存和Executor内存。
堆外内存

有spark.yarn.executor.memeoryOverhead参数设置。如果没有设置,则使用

val executorMemoryOverhead = sparkConf.getInt("spark.yarn.executor.memoryOverhead",math.max((MEMORY_OVERHEAD_FACTOR * executorMemory).toInt, MEMORY_OVERHEAD_MIN))

MEMORY_OVERHEAD_FACTOR = 0.10默认为0.01;

// 最终分配的executor 内存为 两部分的和
val executorMem = args.executorMemory + executorMemoryOverhead

来获得。
spark在一个Executor中的内存分为三部分:
1、execution块,shuffle的数据也会先缓存在这个内存中,满了再写入磁盘中、排序、map的过程也是在这个内存中执行的、聚合、计算的内存。
2、storage块,用于集群中缓存RDD和传播内部数据的内存(cache、persist数据的地方、广播变量)
3、other块,程序执行时预留给自己的内存,如spark程序的对象。

execution块和storage块占Executor的大部分,而other占有一小部分。在spark1.6之后,execution内存和storage内存可以相互借用,提高了内存的spark中内存的使用率,同时也减少了OMM的情况。

**在实际分配Executor内存的计算,需要涉及在yarn上的部署模式**
关于Executor计算的相关公式,见源码:
var executorMemory = 1024 // 默认值,1024MB
val MEMORY_OVERHEAD_FACTOR = 0.10  // OverHead 比例参数,默认0.1
val MEMORY_OVERHEAD_MIN = 384
val executorMemoryOverhead =sparkConf.getInt("spark.yarn.executor.memoryOverhead",
math.max((MEMORY_OVERHEAD_FACTOR * executorMemory).toInt, MEMORY_OVERHEAD_MIN))
// 假设有设置参数,即获取参数,否则使用executorMemoryOverhead 的默认值
val executorMem = args.executorMemory + executorMemoryOverhead
// 最终分配的executor 内存为 两部分的和

提交的脚本:spark-submit --master yarn-cluster --name test --driver-memory 6g --executor-memory 6g
总得大小应该为6144MB+612MB=6756MB
然而实际的开销为7168,这是为什么呢?
这会涉及到规整化因子

规整化因子的介绍

为了易于管理资源和调度资源,Hadoop YARN内置了资源规整化算法,它规定了最小可申请资源量、最大可申请资源量和资源规整化因子,如果应用程序申请的资源量小于最小可申请资源量,则YARN会将其大小改为最小可申请量,也就是说,应用程序获得资源不会小于自己申请的资源,但也不一定相等;如果应用程序申请的资源量大于最大可申请资源量,则会抛出异常,无法申请成功;规整化因子是用来规整化应用程序资源的,应用程序申请的资源如果不是该因子的整数倍,则将被修改为最小的整数倍对应的值,公式为:
ceil(a/b)*b,其中a是应用程序申请的资源,b为规整化因子。

比如,在yarn-site.xml中设置,相关参数如下:
yarn.scheduler.minimum-allocation-mb:最小可申请内存量,默认是1024
yarn.scheduler.minimum-allocation-vcores:最小可申请CPU数,默认是1
yarn.scheduler.maximum-allocation-mb:最大可申请内存量,默认是8096
yarn.scheduler.maximum-allocation-vcores:最大可申请CPU数,默认是4

对于规整化因子,不同调度器不同,具体如下:
FIFO和容量调度器(Capacity Scheduler),规整化因子等于最小可申请资源量,不可单独配置。
Fair Scheduler:规整化因子通过参数yarn.scheduler.increment-allocation-mb和yarn.scheduler.increment-allocation-vcores设置,默认是1024和1。
比如yarn的最小可申请资源内存量为1024,规整因子是1024,如果一个应用程序申请1500内存,则会得到2048,如果规整因子是512,则得到的内存1536。
所以最终分配的内存为:ceil(6756/1024)*1024=7168

Client 和 Cluster 内存分配的差异
在使用Clietn 和 Cluster 两种方式提交时,资源开销占用也是不同的。
不管CLient或CLuster模式下,ApplicationMaster都会占用一个Container来运行;而Client模式下的Container默认有1G内存,1个cpu核,Cluster模式下则使用driver-memory和driver-cpu来指定;

小结:虽然spark中用executor-memory参数控制那个executor的内存,但是,实际分配多少内存,还有一定的处理机制,需要跟踪源码来发掘

1、map过程产生大量对象导致内存溢出

这种溢出的原因:是在单个map中产生了大量的对象导致的。
**解决方法:**通过减少每个task的大小来减少Executor内存中的数量,具体做法是在调用map操作前先调用repartition方法,增大分区数来减少每个分区的大小,再传入map中进行操作。

2、数据不平衡导致内存溢出

数据不平衡除了可能导致内存溢出外,也可能导致性能的问题,解决方法和上面的类似。

3、shuffle后内存溢出

shuffle内存溢出的情况可以说都是shuffle后,shuffle会产生数据倾斜,少数的key内存非常的大,它们都在同一个Executor中计算,导致运算量加大甚至会产生OOM。

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spark作业OOM(Out Of Memory)是指在Spark运行过程,由于内存不足而导致的异常错误。 Spark作业是在集群上并行执行的大规模数据处理任务。在执行过程Spark会将数据加载到内存进行计算,而当数据量过大或计算过程需要消耗大量内存时,就有可能出现OOM错误。 Spark作业OOM原因可以有多种,以下是几个可能的原因和对应的解决办法: 1. 数据量过大:当数据超出了可用内存的限制,就会导致OOM错误。可以尝试增加集群的内存配置或者减小数据量。 2. 内存泄漏:如果Spark作业存在内存泄漏的问题,会导致内存不断增长直至耗尽,并最终触发OOM错误。可以通过分析堆栈和内存使用情况来定位和修复内存泄漏。 3. 并发执行过多:如果同时运行的任务过多,会导致内存资源被过度消耗,从而引发OOM错误。可以通过调整Spark作业的并发度或者限制同时运行的任务数量来避免这个问题。 4. 内存管理不足:Spark默认使用的是分配模式为JVM堆内存模式,并且对内存的分配和回收并不是实时进行的。如果设置的内存预留不足或者分配策略不合理,也会导致OOM错误。可以尝试调整Spark的内存配置参数,如executor.memory、spark.driver.memory等,以及调整垃圾回收机制参数,来优化内存管理。 在解决Spark作业OOM问题时,需要结合具体情况进行分析和调整,一般可以通过适当增加内存、优化算法、合理调整并发度等方式来解决。同时,对于大规模数据处理任务,也可以考虑使用分布式缓存、磁盘存储等方式来降低内存需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值