我正在使用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
在此错误之前,我没有看到任何警告或错误日志。问题是什么?我应该在哪里寻找内存消耗?我看不到SparkUI的存储 TAB。该日志从HDP 2.5
上取自 YARN Resource Manager UI编辑查看容器日志,似乎是java.lang.OutOfMemoryError: GC overhead limit exceeded
我知道如何增加内存,但是我没有任何记忆。我该如何进行笛卡尔/产品与4个数据范围加入,而不会遇到此错误。
我也遇到了这个问题,并尝试通过引用某些博客来解决它。1.运行火花添加Conf Bellow:
--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 '
- 当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 }
-
Psyounggen和Paroldgen均为99%,然后您将获得Java.lang.outofmemoryerror:GC高架限制超过如果创建了更多对象。
-
当更多内存资源可用时,请尝试为执行人或驱动程序添加更多内存:
- 遗嘱执行人记忆10000m
- 驾驶员 - 记忆10000m
-
对于我的情况:Psyounggen的内存比Paroldgen小,导致许多年轻物体进入Paroldgen Memory区域和Finalyparoldgen不可避免。
-
为执行人添加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并行和平行GC
- 如果步骤4和步骤6都完成但仍然会出现错误,则应考虑更改代码。例如,减少ML模型中的迭代时间。
所有容器和AM的日志文件可在
上使用yarn logs -applicationId application_1480922439133_0845_02
如果您只想要AM logs,
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一直在快速连续运行,但无法恢复很多内存。唯一的原因是,要么代码写得不好,而且有很多背参考(这是令人怀疑的,因为您正在执行简单的加入),或者已经达到了内存能力。
原因1
默认情况下,洗牌计数为 200
。过多的洗牌会增加使程序崩溃的复杂性和机会。尝试控制Spark会话中的造成数量。我使用以下代码将计数更改为5
。
implicit val sparkSession = org.apache.spark.sql.SparkSession.builder().enableHiveSupport().getOrCreate()
sparkSession.sql("set spark.sql.shuffle.partitions=5")
另外,如果您使用的是数据框架,并且如果您不重新分配数据框,则执行将在单个执行程序中完成。如果只有1个执行人正在运行一段时间,则纱线将使其他执行者关闭。稍后,如果需要更多内存,尽管Yarn试图重新打电话给其他执行者有时不会出现,但由于内存溢出问题,该过程可能会失败。为了克服这种情况,请尝试在调用操作之前重新分配数据框。
val df = df_temp.repartition(5)
请注意,您可能需要根据您的要求更改洗牌和分区计数。在我的情况下,上述组合有效。
原因2
可能由于内存而发生的可能发生。例如,如果您使用Scala运行Spark命令,并且您正在执行大量SQL语句并导出到CSV。某些蜂巢表中的数据将非常庞大,您必须管理代码中的内存。
示例,考虑以下代码,其中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)
})