Spark Streaming作业运行数天后持续失败的排查与优化咨询
问题根源定位
从报错信息可明确,Application Master(AM)容器内存超出YARN配额:
AM Container for appattempt_1610108774021_0354_000001 exited with exitCode: -104
Failing this attempt.Diagnostics: Container [pid=31537,containerID=container_1610108774021_0354_01_000001] is running beyond physical memory limits. Current usage: 5.8 GB of 5.5 GB physical memory used;
由于你使用--deploy-mode cluster,Spark Driver运行在AM容器中,YARN给AM的内存配额为spark.driver.memory + spark.driver.memoryOverhead。你之前仅调整了spark.executor.memoryOverhead,未针对Driver侧的堆外内存配置优化,这是核心问题。
配置调整方案
1. 优化Driver(AM)内存配置
长期运行的Streaming作业,Driver的堆外内存(如Netty缓冲、直接内存、JNI资源)会持续累积,需显式设置足够的spark.driver.memoryOverhead:
- 适当降低
spark.driver.memory(避免堆内存过大挤占堆外空间),同时调高spark.driver.memoryOverhead:
此时YARN给AM的总内存配额为6G,低于单节点16G内存(预留4G给系统和YARN守护进程),避免资源耗尽。--conf spark.driver.memory=4G \ --conf spark.driver.memoryOverhead=2G
2. 调整Executor资源配置
你的集群有2个数据节点(4核/16G),当前--num-executors 3会导致部分节点运行2个Executor,内存压力过大:
- 调整Executor数量与节点匹配,同时优化每个Executor的内存和核数:
每个Executor总内存为10G,单节点仅运行1个Executor,预留6G内存给系统和AM,避免节点内存过载。--num-executors 2 \ --executor-cores 3 \ --executor-memory 8G \ --conf spark.executor.memoryOverhead=2G
3. 开启Streaming背压机制
防止Receiver接收数据速度过快,导致内存堆积:
--conf spark.streaming.backpressure.enabled=true
排查内存泄漏问题
运行数天后才失败,大概率存在内存泄漏,需进一步排查:
- 开启Spark事件日志(暂时打开,方便分析):
通过Spark UI观察Driver/Executor的内存增长趋势,重点查看堆内存、堆外内存的变化曲线。--conf spark.eventLog.enabled=true - 检查Streaming作业代码:
- 确认
streamingContext.remember()设置的缓存时长是否过长,避免RDD持续占用内存。 - 检查Receiver是否存在未释放的资源(如数据库连接、文件句柄),或全局变量持有大量数据。
- 排查
cache()/persist()的使用场景,避免不必要的内存缓存。
- 确认
- 使用JVM工具分析Driver堆内存:
在节点上执行jmap -histo <Driver PID>,查看对象占比,定位持续增长的对象类型。
最终优化后的提交命令示例
spark-submit --name DWH-CDC-commonJob \ --deploy-mode cluster \ --master yarn \ --conf spark.sql.shuffle.partitions=6 \ --conf spark.eventLog.enabled=true \ --conf spark.sql.caseSensitive=true \ --conf spark.driver.memory=4G \ --conf spark.driver.memoryOverhead=2G \ --class com.aos.Loader \ --jars file:////home/hadoop/lib/* \ --executor-memory 8G \ --conf spark.executor.memoryOverhead=2G \ --conf "spark.alert.duration=4" \ --conf spark.dynamicAllocation.enabled=false \ --num-executors 2 \ --executor-cores 3 \ --files /home/hadoop/log4j.properties,/home/hadoop/application.conf \ --conf "spark.driver.extraJavaOptions=-Dlog4j.configuration=file:log4j.properties" \ --conf "spark.executor.extraJavaOptions=-Dlog4j.configuration=file:log4j.properties" \ --conf spark.streaming.backpressure.enabled=true \ streams_2.11-1.0.jar application.conf
内容的提问来源于stack exchange,提问作者mt_leo

