Spark task过多导致任务运行过慢甚至超时

背景以及现象

本文基于 spark 3.1.2
设置spark.driver.memory=2g
在调试spark sql任务的时候,发现有几个任务产生了40多万个Task,而且任务长期运行不出来。

分析

运行此sql,可以得到如下的dag(我们只截取产生Task多的Stage),由此可以看到是scan的文件太大了(scan了日志文件半年的数据)。
在这里插入图片描述

但是为什么这种情况下会导致任务运行很缓慢甚至会超时呢?
找到driver端,
用jstat -gcutil查看一下对应的gc情况(对应的内存都是调优完后的镜像信息),如下:

  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
 62.02   0.00   9.96  64.72  91.02  94.29    916   13.091    26    0.650   13.742
  0.00  77.27   6.58  64.72  91.02  94.29    917   13.100    26    0.650   13.750
  0.00  77.27  76.70  64.72  91.02  94.29    917   13.100    26    0.650   13.750
  0.00  22.28  45.52  65.65  91.02  94.29    921   13.143    26    0.650   13.794
  0.00  43.36  70.04  65.65  91.02  94.29    923   13.157    26    0.650   13.807
 63.00   0.00  71.39  65.65  91.02  94.29    924   13.165    26    0.650   13.815
  0.00  87.35  42.71  65.65  91.02  94.29    925   13.173    26    0.650   13.823
 21.96   0.00   0.00  66.59  91.02  94.29    930   13.220    26    0.650   13.871
 62.19   0.00   7.41  66.59  91.02  94.29    932   13.235    26    0.650   13.886
 62.19   0.00  65.55  66.59  91.02  94.29    932   13.235    26    0.650   13.886

直接用jmap -heap 命令查看一下对应的堆情况:

Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 4294967296 (4096.0MB)
   NewSize                  = 172621824 (164.625MB)
   MaxNewSize               = 523436032 (499.1875MB)
   OldSize                  = 345374720 (329.375MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 155385856 (148.1875MB)
   used     = 115967072 (110.59481811523438MB)
   free     = 39418784 (37.592681884765625MB)
   74.63167818826444% used
Eden Space:
   capacity = 138149888 (131.75MB)
   used     = 100616000 (95.95489501953125MB)
   free     = 37533888 (35.79510498046875MB)
   72.83103986302181% used
From Space:
   capacity = 17235968 (16.4375MB)
   used     = 15351072 (14.639923095703125MB)
   free     = 1884896 (1.797576904296875MB)
   89.06417092442966% used
To Space:
   capacity = 17235968 (16.4375MB)
   used     = 0 (0.0MB)
   free     = 17235968 (16.4375MB)
   0.0% used
concurrent mark-sweep generation:
   capacity = 3127533568 (2982.6484375MB)
   used     = 2325934584 (2218.1840744018555MB)
   free     = 801598984 (764.4643630981445MB)
   74.36961213776492% used

可以看到driver端的内存 full gc频次有点高,而且内存增长的很厉害。

再次 我们用jmap -dump:format=b,file=heapdump.hprof命令dump内存的堆信息,我们分析一下,用MAT打开,我们可以看到如下的信息:
在这里插入图片描述
在这里插入图片描述
可以看到 taskSetManager的内就占用了700M。而且这任务才只是开始运行,所以后续很长一段时间,必然会占比较长的时间段。
而且这只是一个taskSetManager的内存占用,如果在足够复杂的sql下,有可能会有类似的taskSetManaget会有多个(taskSetManager是一个stage所有task的总和)。

结论以及解决方法

所以在这种情况下,如果业务上改变不了,我们就得增加内存,在笔者的情况下,增加driver内存到4g就能很好的解决,且运行的速度很快。

spark.driver.memory=4g
### Spark任务失败的原因分析及解决方案 Spark任务失败通常由多种原因引起,例如资源不足、任务逻辑错误、数据倾斜或外部依赖问题等。以下是针对`org.apache.spark.SparkException: Job aborted due to stage failure`以及相关错误代码的详细分析和解决方法。 #### 1. 错误分析 错误信息表明,任务在某个阶段(Stage)中失败,并且任务重试了4次后仍然未能成功。具体错误包括: - **Task 0 in stage 4.0 failed 4 times**: 表明任务在第4个阶段中的第0个任务连续失败4次[^1]。 - **Lost task UnknownReason**: 这可能与节点资源分配失败或任务执行过程中发生未知异常有关[^2]。 - **Execution Error return code 3**: 返回码3通常表示任务执行期间出现严重错误[^3]。 - **org.apache.hadoop.hive.ql.exec.spark.SparkTask Spark job failed runtime solution**: 表明Hive on Spark任务运行时出现问题,可能是由于Hive元数据配置错误或Hadoop文件系统访问失败导致[^4]。 #### 2. 常见原因及解决方法 ##### (1)资源不足 如果集群资源不足(如内存或CPU),可能导致任务无法正常执行。检查以下内容: - 配置参数是否合理:`spark.executor.memory`, `spark.driver.memory`, `spark.executor.cores`等。 - 调整并行度:通过设置`spark.sql.shuffle.partitions`来优化任务的分区数[^5]。 ```python spark.conf.set("spark.sql.shuffle.partitions", "200") ``` ##### (2)数据倾斜 数据倾斜会导致某些任务处理的数据量过大,从而引发超时或OOM(Out of Memory)。可以通过以下方式缓解: - 使用`salting`技术打散数据。 - 对大表进行预聚合操作。 - 调整Shuffle过程中的分区策略。 ```python # 示例:对key添加随机前缀以分散数据 import random df = df.withColumn("salted_key", concat(col("key"), lit("_"), lit(random.randint(1, 10)))) ``` ##### (3)任务逻辑错误 检查任务代码是否存在逻辑错误,例如空指针异常或非法输入数据。确保输入数据的质量,并捕获潜在的异常。 ```python try: # 执行任务逻辑 result = df.groupBy("key").agg(sum("value")) except Exception as e: print(f"Error occurred: {e}") ``` ##### (4)外部依赖问题 如果任务依赖于HDFS或其他外部系统,可能因网络延迟或权限问题导致失败。验证以下内容: - HDFS路径是否正确。 - 是否存在权限限制。 - 网络连接是否稳定。 #### 3. 日志排查 通过查看Spark日志,可以定位具体的错误原因。重点关注以下日志文件: - `stderr`: 捕获任务执行期间的标准错误输出。 - `stdout`: 记录任务的标准输出。 - `driver.log`和`executor.log`: 包含驱动程序和执行器的详细日志信息。 ```bash # 查看日志 cat /path/to/spark/logs/stderr ``` #### 4. 参数调优 根据实际场景调整以下关键参数: - `spark.task.maxFailures`: 设置任务的最大重试次数。 - `spark.network.timeout`: 增加网络超时时间。 - `spark.speculation`: 启用推测执行以减少慢任务的影响。 ```python spark.conf.set("spark.task.maxFailures", "10") spark.conf.set("spark.network.timeout", "600s") spark.conf.set("spark.speculation", "true") ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值