Dataproc PySpark作业日志报错但持续运行数小时不退出
问题排查与解决方案
你看到的Unable to stop heartbeater、shutdown hook线程空指针异常都属于次生报错,不是作业卡住的根因:这些报错是Executor已经异常退出、触发JVM关闭钩子时,因为心跳组件等还没完成初始化就被销毁才抛出的噪音日志,不会直接导致作业长时间挂起。
结合你提到的「数据量小、随机触发、重跑大概率正常、作业不自动终止持续运行数小时」的特征,以及日志中Container from a bad node、容器prelaunch阶段就以exit code 1退出的记录,对应问题和解决方法如下:
- 节点偶发初始化/资源异常导致容器启动失败
如果你开了集群自动伸缩、使用了抢占式/可突发实例,小概率会遇到节点刚加入集群就被云厂商回收、临时盘挂载失败、拉取作业依赖网络闪断的情况,Executor容器在prelaunch阶段直接退出。默认配置下Spark不会因为这类偶发启动失败终止作业,Driver会持续循环申请新的Executor,如果一直申请不到可用容器就会无限挂起。
对应配置调整:- 提交作业时添加参数
spark.yarn.max.executor.failures=8、spark.executor.failuresValidityInterval=120s,限制2分钟内Executor失败超过8次就直接终止作业,避免无限等待 - 添加参数
spark.network.timeout=300s、spark.executor.heartbeatInterval=60s,避免网络闪断时Driver长时间等待失联Executor - 如果使用抢占式实例,添加参数
spark.yarn.am.waitTime=90s,等节点初始化稳定后再调度任务
- 提交作业时添加参数
- Spark版本已知bug导致退出事件回调异常
日志中Executor停止阶段的空指针是Spark 3.1、3.2早期版本的已知问题:如果Executor还没完成初始化就被YARN杀掉,关闭钩子访问未初始化的心跳对象会抛出NPE,既会掩盖容器真正的退出原因,还可能导致YARN的容器退出事件回调失败,Driver收不到Executor退出信号,一直等待任务完成。
对应解决:- 将Dataproc集群镜像升级到2.1.x及以上版本(内置Spark 3.3+),该版本已经修复了Executor关闭阶段的空指针问题,既可以正常打印容器真实退出原因,也不会出现事件回调卡住的问题
- 如果暂时无法升级镜像,提交作业时添加参数
spark.executor.extraJavaOptions=-Dspark.shutdown.hook.timeout=30s,强制关闭钩子超时退出,避免进程卡住
- 集群资源碎片化/节点磁盘不健康导致容器启动失败
小数据量作业如果开了动态资源分配,会频繁申请、释放小规格Executor容器,容易在节点上产生资源碎片,新容器申请到资源配额但实际启动时内存、磁盘不足,会在prelaunch阶段直接退出。这类启动阶段的失败不会被计入任务失败计数,Driver会一直循环申请新容器导致作业挂住。
对应排查&解决:- 作业卡住时登录YARN ResourceManager UI,查看失败容器所在节点的磁盘使用率、剩余内存,如果节点磁盘使用率超过90%会触发YARN健康检查,禁止新容器调度,需要清理节点上的过期日志、临时文件
- 小数据量作业直接关闭动态分配,提交时添加参数
spark.dynamicAllocation.enabled=false,固定申请2-4个小规格Executor即可,避免频繁申请释放容器产生资源碎片 - 给集群配置节点自动健康检查和替换策略,自动剔除磁盘满、服务异常的节点
快速定位根因技巧:下次问题复现时,不要只看Driver端打印的截断日志,直接去YARN上找到对应失败容器的完整启动日志,查看同目录下
launch_container.sh的执行输出,就能看到容器prelaunch阶段失败的真实原因(依赖拉取失败、磁盘不足、节点被回收等)。
内容的提问来源于stack exchange,提问作者Help_me_a_bit
相关产品推荐
相关产品推荐

