【问题标题】:spark on yarn, Container exited with a non-zero exit code 143纱线上的火花,容器以非零退出代码 143 退出
【发布时间】:2017-04-21 12:05:42
【问题描述】:

我正在使用 HDP 2.5,以纱线集群模式运行 spark-submit

我尝试使用数据框交叉连接生成数据。 即

val generatedData = df1.join(df2).join(df3).join(df4)
generatedData.saveAsTable(...)....

df1存储级别为 MEMORY_AND_DISK

df2,df3,df4存储级别为 MEMORY_ONLY

df1 有更多的记录,即 500 万条,而 df2 到 df4 最多有 100 条记录。 这样做我的解释平原将使用 BroadcastNestedLoopJoin 解释计划获得更好的性能。

由于某种原因,它总是失败。我不知道如何调试它以及内存爆炸的位置。

错误日志输出:

16/12/06 19:44:08 WARN YarnAllocator: Container marked as failed: container_e33_1480922439133_0845_02_000002 on host: hdp4. Exit status: 143. Diagnostics: Container killed on request. Exit code is 143
Container exited with a non-zero exit code 143
Killed by external signal

16/12/06 19:44:08 WARN YarnSchedulerBackend$YarnSchedulerEndpoint: Container marked as failed: container_e33_1480922439133_0845_02_000002 on host: hdp4. Exit status: 143. Diagnostics: Container killed on request. Exit code is 143
Container exited with a non-zero exit code 143
Killed by external signal

16/12/06 19:44:08 ERROR YarnClusterScheduler: Lost executor 1 on hdp4: Container marked as failed: container_e33_1480922439133_0845_02_000002 on host: hdp4. Exit status: 143. Diagnostics: Container killed on request. Exit code is 143
Container exited with a non-zero exit code 143
Killed by external signal

16/12/06 19:44:08 WARN TaskSetManager: Lost task 1.0 in stage 12.0 (TID 19, hdp4): ExecutorLostFailure (executor 1 exited caused by one of the running tasks) Reason: Container marked as failed: container_e33_1480922439133_0845_02_000002 on host: hdp4. Exit status: 143. Diagnostics: Container killed on request. Exit code is 143
Container exited with a non-zero exit code 143
Killed by external signal

在出现此错误之前,我没有看到任何 WARN 或 ERROR 日志。 问题是什么?我应该在哪里寻找内存消耗? 我在 SparkUI 的 Storage 选项卡上看不到任何内容。 日志取自 HDP 2.5 上的 yarn 资源管理器 UI

编辑 查看容器日志,好像是java.lang.OutOfMemoryError: GC overhead limit exceeded

我知道如何增加内存,但我已经没有任何内存了。 如何在不出现此错误的情况下使用 4 个数据框进行笛卡尔/产品连接。

【问题讨论】:

  • 如果数据帧的大小如您所建议的那样(5e6、100、100、100),笛卡尔积将有大约 5e12 条记录,即 5 万亿。您没有提到列数,但是如果您有一个整数列,则需要 TB 的存储空间。如果您有多个列,则连接的数据库可能需要数百或数千 TB。这真的是你想要的吗?
  • 1 列。这是一个数据生成器实用程序,内存爆炸。

标签: apache-spark hive hadoop-yarn hortonworks-data-platform


【解决方案1】:

所有容器和am的日志文件都可用,

yarn logs -applicationId application_1480922439133_0845_02

如果您只想要 AM 日志,

yarn logs -am -applicationId application_1480922439133_0845_02

如果您想查找为此作业运行的容器,

yarn logs -applicationId application_1480922439133_0845_02|grep container_e33_1480922439133_0845_02

如果您只想要一个容器日志,

yarn logs -containerId container_e33_1480922439133_0845_02_000002

为了使这些命令起作用,日志聚合必须设置为 true,否则您将不得不从各个服务器目录获取日志。

更新 除了尝试交换之外,您无能为力,但这会大大降低性能。

GC 开销限制意味着,GC 一直在快速连续运行,但无法恢复太多内存。唯一的原因是,要么代码写得不好并且有很多反向引用(这是值得怀疑的,因为你正在做简单的连接),或者内存容量已经达到。

【讨论】:

  • 感谢您的帮助,我已经找到了问题所在。如果您知道如何解决它,我将不胜感激(我正在更新问题)
【解决方案2】:

我也遇到了这个问题,并尝试通过参考一些博客来解决它。 1. 运行 spark add conf 如下:

--conf 'spark.driver.extraJavaOptions=-XX:+UseCompressedOops -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps' \
--conf 'spark.executor.extraJavaOptions=-XX:+UseCompressedOops -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC  ' \
  1. 当 jvm GC 时,你会得到如下信息:
Heap after GC invocations=157 (full 98):
 PSYoungGen      total 940544K, used 853456K [0x0000000781800000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 860160K, 99% used [0x0000000781800000,0x00000007b5974118,0x00000007b6000000)
  from space 80384K, 0% used [0x00000007b6000000,0x00000007b6000000,0x00000007bae80000)
  to   space 77824K, 0% used [0x00000007bb400000,0x00000007bb400000,0x00000007c0000000)
 ParOldGen       total 2048000K, used 2047964K [0x0000000704800000, 0x0000000781800000, 0x0000000781800000)
  object space 2048000K, 99% used [0x0000000704800000,0x00000007817f7148,0x0000000781800000)
 Metaspace       used 43044K, capacity 43310K, committed 44288K, reserved 1087488K
  class space    used 6618K, capacity 6701K, committed 6912K, reserved 1048576K  
}
  1. PSYoungGen 和 ParOldGen 都是 99%,然后你会得到 java.lang.OutOfMemoryError: GC overhead limit exceeded 如果创建了更多对象。

  2. 当有更多内存资源可用时,尝试为执行程序或驱动程序添加更多内存:

--executor-memory 10000m \
--driver-memory 10000m \

  1. 对于我的情况:PSYoungGen 的内存比 ParOldGen 小,这会导致许多年轻对象进入 ParOldGen 内存区域并最终进入 ParOldGen 不可用。所以出现 java.lang.OutOfMemoryError: Java heap space 错误。

  2. 为执行者添加conf:

'spark.executor.extraJavaOptions=-XX:NewRatio=1 -XX:+UseCompressedOops -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps '

-XX:NewRatio=比率 率 = ParOldGen/PSYoungGen

这取决于。你可以尝试像 GC 策略

-XX:+UseSerialGC :Serial Collector 
-XX:+UseParallelGC :Parallel Collector
-XX:+UseParallelOldGC :Parallel Old collector 
-XX:+UseConcMarkSweepGC :Concurrent Mark Sweep 

Java Concurrent and Parallel GC

  1. 如果第 4 步和第 6 步都已完成,但仍然出现错误,则应考虑更改代码。例如,减少 ML 模型中的迭代次数。

【讨论】:

    【解决方案3】:

    原因 1


    默认情况下,随机播放计数为200。洗牌次数过多会增加程序崩溃的复杂性和机会。尝试控制 spark 会话中的随机播放次数。我使用以下代码将计数更改为5

    implicit val sparkSession = org.apache.spark.sql.SparkSession.builder().enableHiveSupport().getOrCreate()    
    sparkSession.sql("set spark.sql.shuffle.partitions=5")
    

    此外,如果您正在使用数据帧并且不重新分区数据帧,则执行将在单个执行程序中完成。如果只有 1 个 executor 运行了一段时间,那么 yarn 会使其他 executor 关闭。稍后如果需要更多内存,虽然 yarn 尝试重新调用其他执行程序,但有时执行程序不会出现,因此该进程可能会因内存溢出问题而失败。要克服这种情况,请尝试在调用操作之前重新分区数据帧。

    val df = df_temp.repartition(5)
    

    请注意,您可能需要根据您的要求更改随机播放和分区计数。就我而言,上述组合有效。

    原因 2


    这可能是由于内存没有按时清除而发生的。例如,如果您正在使用 Scala 运行 spark 命令,并且正在执行一堆 sql 语句并导出到 csv。某些 Hive 表中的数据会非常庞大​​,您必须在代码中管理内存。

    例如,考虑下面的代码,其中lst_Sqls 是一个包含一组 sql 命令的列表

    lst_Sqls.foreach(sqlCmd => spark.sql(sqlCmd).coalesce(1).write.format("com.databricks.spark.csv").option("delimiter","|").save("s3 path..."))
    

    当您运行此命令时,有时您最终会看到相同的错误。这是因为虽然 spark 清除了内存,但它以一种懒惰的方式执行此操作,即您的循环将继续,但 spark 可能会在稍后的某个时间点清除内存。

    在这种情况下,您需要在代码中管理内存,即在执行每个命令后清除内存。为此,让我们稍微改变一下我们的代码。我已经在下面的代码中注释了每一行的作用。

     lst_Sqls.foreach(sqlCmd => 
     {          
          val df = spark.sql(sqlCmd) 
          // Store the result in in-memory. If in-memory is full, then it stored to HDD
          df.persist(StorageLevel.MEMORY_AND_DISK)
          // Export to csv from Dataframe
          df.coalesce(1).write.format("com.databricks.spark.csv").save("s3 path")
          // Clear the memory. Only after clearing memory, it will jump to next loop
          df.unpersist(blocking = true)
     })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多