1、你在工作当中有遇到内存溢出问题吗?你是如何解决的?
回答思路:先解释spark的内存模型,再分情况介绍不同情况下的解决方案。总体思想是根据内存模型找出不够的那一块内存,要么提升占比,要么整体增加。
oom通常出现在execution内存中,因为storage这块内存在放满之后,会直接丢弃内存中旧的数据,对性能有点影响但不会导致oom。存储内存和执行内存可以互相借用内存空间。
而spark的oom问题主要分为三种情况:
①map执行后的内存溢出
--场景:maptask所运行的executor内存溢出。
增加堆内内存,申请的堆外内存也会随之增加
--executor -memory
增加堆外内存
--conf spark.excutor.memoryoverhead 2048
默认申请的堆外内存是Executor内存的10%。
②shuffle后内存溢出
reduce task去map一边拉取数据,一边聚合。reduce端有一块聚合内存,executor memory *0.2
解决方案:增加reduce聚合内存的比例,设置spark.shuffle.memoryfraction
增加executor memory的大小
减少reduce task每次拉取的数据量,设置spark.reducer.maxSizeInFlight 24m
③driver内存溢出
--场景一:用户在Dirver端口生成大对象,比如创建了一个大的集合数据结构
解决思路:Ⅰ将大对象转换成Executor端加载,比如调用sc.textfile
Ⅱ评估大对象占用的内存,增加dirver-menory的值
--场景二:从Executor端收集数据(collect)回Dirver端
解决思路:Ⅰ本身不建议将大的数据从executor端,collect回来。建议将driver端对collect回来的数据所作的操作,转换成executor端rdd操作
Ⅱ若无法避免,估算collect需要的内存,相应增加driver-memory的值
--场景三:spark自身框架的消耗
主要由spark UI数据消耗,取决于作业的累计task个数
解决思路:Ⅰ从hdfs load的parition是自动计算,但在过滤之后,已经大大减少了数据量,此时可以缩小partitions。
Ⅱ通过参数spark.ui.retainedStages/spark.ui.retainedjobs控制(默认1000)
2、shuffle file not found可能是什么原因导致的报错?
产生该报错的原因可能是后一个stage的task从上一个stage的task所在的executor拉取数据,但是上一个stage正在执行GC,导致数据没有拉渠道,出现该错误。可以通过调整拉取的次数和间隔时间来避免此类事件发生。
val conf =new SparkConf()
.set("spark.shuffle.io.maxRetries","6')
.set("spark.shuffle.io.retrywait","60s")
3、栈溢出?
yarn-client模式下,Dirver是运行在本地机器上的,spark使用的jvm的permGen是128m,可能在client上测试没有问题
yarn-cluster模式下,Dirver是运行在集群的某个节点上,使用的是没有经过配置的默认配置,PermGen永久代大小为82m。运行时报栈溢出。
--解决方案:在spark-submit脚本中对相关参数进行设置
--conf spark.dirver.extraJavaOptions="-xx:PerSize=128M -xx:MaxPermSize=256m"