You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spark3.1.2 standalone集群s3a目录提交器OOM无法创建线程问题求助

Spark 3.1.2启用s3a directory committer后Driver OOM(线程数超限制)问题排查

问题背景

使用Spark 3.1.2 standalone集群,启用s3a directory committer后作业稳定性和性能有明显提升,但近期频繁出现Driver OOM错误,报错为无法创建原生线程。

错误日志

An error occurred while calling None.org.apache.spark.api.java.JavaSparkContext.

: java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached
    at java.base/java.lang.Thread.start0(Native Method)
    at java.base/java.lang.Thread.start(Thread.java:803)
    at java.base/java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:937)
    at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1343)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:118)
    at java.base/java.util.concurrent.Executors$DelegatedExecutorService.submit(Executors.java:714)
    at org.apache.spark.rpc.netty.DedicatedMessageLoop.$anonfun$new$1(MessageLoop.scala:174)
    at org.apache.spark.rpc.netty.DedicatedMessageLoop.$anonfun$new$1$adapted(MessageLoop.scala:173)
    at scala.collection.immutable.Range.foreach(Range.scala:158)
    at org.apache.spark.rpc.netty.DedicatedMessageLoop.<init>(MessageLoop.scala:173)
    at org.apache.spark.rpc.netty.Dispatcher.liftedTree1$1(Dispatcher.scala:75)
    at org.apache.spark.rpc.netty.Dispatcher.registerRpcEndpoint(Dispatcher.scala:72)
    at org.apache.spark.rpc.netty.NettyRpcEnv.setupEndpoint(NettyRpcEnv.scala:136)
    at org.apache.spark.storage.BlockManager.<init>(BlockManager.scala:231)
    at org.apache.spark.SparkEnv$.create(SparkEnv.scala:394)
    at org.apache.spark.SparkEnv$.createDriverEnv(SparkEnv.scala:189)
    at org.apache.spark.SparkContext.createSparkEnv(SparkContext.scala:277)
    at org.apache.spark.SparkContext.<init>(SparkContext.scala:458)
    at org.apache.spark.api.java.JavaSparkContext.<init>(JavaSparkContext.scala:58)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
    at py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:247)
    at py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357)
    at py4j.Gateway.invoke(Gateway.java:238)
    at py4j.commands.ConstructorCommand.invokeConstructor(ConstructorCommand.java:80)
    at py4j.commands.ConstructorCommand.execute(ConstructorCommand.java:69)
    at py4j.GatewayConnection.run(GatewayConnection.java:238)
    at java.base/java.lang.Thread.run(Thread.java:834)

排查信息

  1. 线程栈Dump显示Driver上存在超过5000个处于WAITING状态的s3-committer-pool线程,远超配置的线程数上限,部分线程信息如下:
Thread ID   Thread Name Thread State    Thread Locks
1047    s3-committer-pool-0 WAITING 
1449    s3-committer-pool-0 WAITING 
1468    s3-committer-pool-0 WAITING 
1485    s3-committer-pool-0 WAITING 
1505    s3-committer-pool-0 WAITING 
1524    s3-committer-pool-0 WAITING 
1529    s3-committer-pool-0 WAITING 
1544    s3-committer-pool-0 WAITING 
1549    s3-committer-pool-0 WAITING 
1809    s3-committer-pool-0 WAITING 
1972    s3-committer-pool-0 WAITING 
1998    s3-committer-pool-0 WAITING 
2022    s3-committer-pool-0 WAITING 
2043    s3-committer-pool-0 WAITING 
2416    s3-committer-pool-0 WAITING 
2453    s3-committer-pool-0 WAITING 
2470    s3-committer-pool-0 WAITING 
2517    s3-committer-pool-0 WAITING 
2534    s3-committer-pool-0 WAITING 
2551    s3-committer-pool-0 WAITING 
2580    s3-committer-pool-0 WAITING 
2597    s3-committer-pool-0 WAITING 
2614    s3-committer-pool-0 WAITING 
2631    s3-committer-pool-0 WAITING 
2726    s3-committer-pool-0 WAITING 
2743    s3-committer-pool-0 WAITING 
2763    s3-committer-pool-0 WAITING 
2780    s3-committer-pool-0 WAITING 
2819    s3-committer-pool-0 WAITING 
2841    s3-committer-pool-0 WAITING 
2858    s3-committer-pool-0 WAITING 
2875    s3-committer-pool-0 WAITING 
2925    s3-committer-pool-0 WAITING 
2942    s3-committer-pool-0 WAITING 
2963    s3-committer-pool-0 WAITING 
2980    s3-committer-pool-0 WAITING 
3020    s3-committer-pool-0 WAITING 
3037    s3-committer-pool-0 WAITING 
3055    s3-committer-pool-0 WAITING 
3072    s3-committer-pool-0 WAITING 
3127    s3-committer-pool-0 WAITING 
3144    s3-committer-pool-0 WAITING 
3163    s3-committer-pool-0 WAITING 
3180    s3-committer-pool-0 WAITING 
3222    s3-committer-pool-0 WAITING 
3242    s3-committer-pool-0 WAITING 
3259    s3-committer-pool-0 WAITING 
3278    s3-committer-pool-0 WAITING 
3418    s3-committer-pool-0 WAITING 
3435    s3-committer-pool-0 WAITING 
3452    s3-committer-pool-0 WAITING 
3469    s3-committer-pool-0 WAITING 
3486    s3-committer-pool-0 WAITING 
3491    s3-committer-pool-0 WAITING 
3501    s3-committer-pool-0 WAITING 
3508    s3-committer-pool-0 WAITING 
4029    s3-committer-pool-0 WAITING 
4093    s3-committer-pool-0 WAITING 
4658    s3-committer-pool-0 WAITING 
4666    s3-committer-pool-0 WAITING 
4907    s3-committer-pool-0 WAITING 
5102    s3-committer-pool-0 WAITING 
5119    s3-committer-pool-0 WAITING 
5158    s3-committer-pool-0 WAITING 
5175    s3-committer-pool-0 WAITING 
5192    s3-committer-pool-0 WAITING 
5209    s3-committer-pool-0 WAITING 
5226    s3-committer-pool-0 WAITING 
5395    s3-committer-pool-0 WAITING 
5634    s3-committer-pool-0 WAITING 
5651    s3-committer-pool-0 WAITING 
5668    s3-committer-pool-0 WAITING 
5685    s3-committer-pool-0 WAITING 
5702    s3-committer-pool-0 WAITING 
5722    s3-committer-pool-0 WAITING 
5739    s3-committer-pool-0 WAITING 
6144    s3-committer-pool-0 WAITING 
6167    s3-committer-pool-0 WAITING 
6289    s3-committer-pool-0 WAITING 
6588    s3-committer-pool-0 WAITING 
6628    s3-committer-pool-0 WAITING 
6645    s3-committer-pool-0 WAITING 
6662    s3-committer-pool-0 WAITING 
6675    s3-committer-pool-0 WAITING 
6692    s3-committer-pool-0 WAITING 
6709    s3-committer-pool-0 WAITING 
7049    s3-committer-pool-0 WAITING 
  1. 当前s3a相关配置如下,配置的线程数上限远低于实际观测到的线程数:
fs.s3a.threads.max  100 
fs.s3a.connection.maximum  1000 
fs.s3a.committer.threads 16   
fs.s3a.max.total.tasks  5
fs.s3a.committer.name   directory
fs.s3a.fast.upload.buffer                 disk
io.file.buffer.size                                1048576
mapreduce.outputcommitter.factory.scheme.s3a    - org.apache.hadoop.fs.s3a.commit.S3ACommitterFactory
  1. 已测试多个版本的spark-hadoop-cloud依赖,问题均可稳定复现。

问题成因

  1. 核心原因为Hadoop已知bug HADOOP-17260:s3a committer绑定的线程池在S3AFileSystem实例关闭时没有被正确销毁,每初始化一个新的S3AFileSystem实例就会生成一个全新的s3-committer-pool线程池,闲置线程无法回收最终堆积到数千个,超出系统进程资源限制触发OOM。
  2. 你当前测试的所有spark-hadoop-cloud版本对应的底层Hadoop依赖均未合入该bug的修复逻辑,因此更换依赖包后问题仍然稳定复现。
  3. Spark Driver运行作业过程中会频繁创建新的S3AFileSystem实例访问S3存储,加速了线程泄漏的速度,短时间内就能达到进程线程数上限。

修复方案

根治方案

升级底层Hadoop依赖到3.3.1及以上版本,该版本已经合入HADOOP-17260的修复逻辑,线程池会随FileSystem实例关闭正常销毁,不会出现线程堆积问题。若使用CDH发行版,升级到7.2.15及以上版本即可解决问题。

临时规避方案

如果暂时无法升级Hadoop版本,可以通过添加以下配置强制S3AFileSystem实例全局复用,避免频繁创建新实例触发线程泄漏:

spark.hadoop.fs.s3a.impl.disable.cache false
spark.hadoop.fs.s3a.cache.max.size 20

该配置会让Spark全局复用已创建的S3AFileSystem实例,大幅降低新实例创建频率,缓解线程堆积速度。

临时缓解方案

调高Driver进程的ulimit最大线程数限制(将ulimit -u参数调整到10000以上),可以避免作业短时间内崩溃,但无法彻底解决线程泄漏问题,适合作为过渡方案使用。


内容的提问来源于stack exchange,提问作者Ofer Eliassaf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 05:36:03