Apache Spark:作业因阶段失败中止:“TID x 因未知原因失败”
我遇到了一些奇怪的错误信息,我觉得这可能和内存有关,但我很难找到具体原因,希望能得到专家的指导。
我有一个由两台机器组成的Spark集群(版本1.0.1)。这两台机器都有8个核心,其中一台有16GB内存,另一台有32GB内存(32GB的是主节点)。我的应用程序需要计算图像中像素之间的相似度,不过到目前为止,我测试的图像最大只有1920x1200,最小的只有16x16。
我确实需要调整一些内存和并行设置,否则会出现明确的内存溢出错误。在spark-default.conf文件中,我做了如下设置:
spark.executor.memory 14g
spark.default.parallelism 32
spark.akka.frameSize 1000
在spark-env.sh文件中,我也进行了相应的调整:
SPARK_DRIVER_MEMORY=10G
不过,即使这样设置,我还是收到了很多关于“丢失任务ID”的警告(没有任务成功完成),并且还有丢失的执行器,这些警告重复了4次,直到我最终收到以下错误信息并崩溃:
14/07/18 12:06:20 INFO TaskSchedulerImpl: Cancelling stage 0
14/07/18 12:06:20 INFO DAGScheduler: Failed to run collect at /home/user/Programming/PySpark-Affinities/affinity.py:243
Traceback (most recent call last):
File "/home/user/Programming/PySpark-Affinities/affinity.py", line 243, in <module>
lambda x: np.abs(IMAGE.value[x[0]] - IMAGE.value[x[1]])
File "/net/antonin/home/user/Spark/spark-1.0.1-bin-hadoop2/python/pyspark/rdd.py", line 583, in collect
bytesInJava = self._jrdd.collect().iterator()
File "/net/antonin/home/user/Spark/spark-1.0.1-bin-hadoop2/python/lib/py4j-0.8.1-src.zip/py4j/java_gateway.py", line 537, in __call__
File "/net/antonin/home/user/Spark/spark-1.0.1-bin-hadoop2/python/lib/py4j-0.8.1-src.zip/py4j/protocol.py", line 300, in get_return_value
py4j.protocol.Py4JJavaError: An error occurred while calling o27.collect.
: org.apache.spark.SparkException: Job aborted due to stage failure: Task 0.0:13 failed 4 times, most recent failure: TID 32 on host master.host.univ.edu failed for unknown reason
Driver stacktrace:
at org.apache.spark.scheduler.DAGScheduler.org$apache$spark$scheduler$DAGScheduler$$failJobAndIndependentStages(DAGScheduler.scala:1044)
at org.apache.spark.scheduler.DAGScheduler$$anonfun$abortStage$1.apply(DAGScheduler.scala:1028)
at org.apache.spark.scheduler.DAGScheduler$$anonfun$abortStage$1.apply(DAGScheduler.scala:1026)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:47)
at org.apache.spark.scheduler.DAGScheduler.abortStage(DAGScheduler.scala:1026)
at org.apache.spark.scheduler.DAGScheduler$$anonfun$handleTaskSetFailed$1.apply(DAGScheduler.scala:634)
at org.apache.spark.scheduler.DAGScheduler$$anonfun$handleTaskSetFailed$1.apply(DAGScheduler.scala:634)
at scala.Option.foreach(Option.scala:236)
at org.apache.spark.scheduler.DAGScheduler.handleTaskSetFailed(DAGScheduler.scala:634)
at org.apache.spark.scheduler.DAGSchedulerEventProcessActor$$anonfun$receive$2.applyOrElse(DAGScheduler.scala:1229)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498)
at akka.actor.ActorCell.invoke(ActorCell.scala:456)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237)
at akka.dispatch.Mailbox.run(Mailbox.scala:219)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
14/07/18 12:06:20 INFO DAGScheduler: Executor lost: 4 (epoch 4)
14/07/18 12:06:20 INFO BlockManagerMasterActor: Trying to remove executor 4 from BlockManagerMaster.
14/07/18 12:06:20 INFO BlockManagerMaster: Removed 4 successfully in removeExecutor
user@master:~/Programming/PySpark-Affinities$
如果我运行一个非常小的图像(16x16),它似乎能够正常完成(给我预期的输出,没有抛出任何异常)。但是,在运行的应用程序的错误日志中,它的状态显示为“被终止”,最后的消息是“错误:粗粒度执行器后端:驱动程序断开连接”。如果我运行任何更大的图像,就会出现我之前提到的异常。
此外,如果我使用 master=local[*]
进行spark-submit,除了仍然需要设置之前提到的内存选项外,它可以处理任何大小的图像(我已经独立测试了这两台机器;它们在以 local[*]
运行时都会这样)。
有没有人知道这到底是怎么回事?
2 个回答
这个问题真是难以发现!问题出在Spark的版本1.0.1上,它没有明确指出实际的错误,而是把错误称为“unknownReason”,这让我们很难找到问题所在。
你可以用这个命令来运行Spark应用:--driver-class-path path_to_spark_application,这样就能得到导致任务失败的正确错误信息。我的错误是JsResultException。
我想这个问题在Spark 1.6及以上版本中已经解决了。
如果我每次问别人“你有没有试过把分区数量增加到至少每个CPU有4个任务,甚至高达1000个分区?”都能得到一分钱的话,那我肯定会变得很富有。那么,你试过增加分区数量吗?
另外,我发现一些方法可以帮助解决奇怪的关联问题:
- 帧大小设置为500
- 请求超时时间设置为100
- 工作超时时间设置为150(这样可以处理大量的垃圾回收挂起问题)
- 调整内存缓存(可以参考Spark java.lang.OutOfMemoryError: Java heap space)
有时候,通过使用用户界面查看特定工作节点的错误日志,你能获得更详细的错误信息。
更新:自从Spark 1.0.0版本后,无法通过用户界面找到Spark日志,你需要请系统管理员或运维人员帮忙,因为日志的位置完全没有文档说明。