使用Kafka直接流来消除Yarn上的堆内存泄漏

时间:2015-07-13 18:01:45

标签: apache-spark apache-kafka spark-streaming yarn apache-spark-1.4

我在Yarn(Apache发行版2.6.0)上使用java 1.8.0_45以及Kafka直接流运行spark streaming 1.4.0。我也使用spark和scala 2.11支持。

我看到的问题是驱动程序和执行程序容器都在逐渐增加物理内存使用量,直到纱线容器终止它为止。我在驱动程序中配置了高达192M堆和384堆堆空间,但最终耗尽了它

对于常规GC循环,堆内存似乎没问题。在任何此类运行中都没有遇到OutOffMemory

事实上,我仍然没有在kafka队列上产生任何流量。这是我正在使用的代码

./bin/spark-submit --class com.rasa.cloud.prototype.spark.SimpleSparkStreaming \
--conf spark.yarn.executor.memoryOverhead=256 \
--conf spark.yarn.driver.memoryOverhead=384 \
--conf spark.kafka.topic.name=test \
--conf spark.kafka.broker.list=172.31.45.218:9092 \
--conf spark.batch.window.size=1 \
--conf spark.app.name="Simple Spark Kafka application" \
--master yarn-cluster \
--num-executors 1 \
--driver-memory 192m \
--executor-memory 128m \
--executor-cores 1 \
/home/centos/spark-poc/target/lib/spark-streaming-prototype-0.0.1-SNAPSHOT.jar 

我在CentOS 7上运行。用于spark提交的命令是

{{1}}

非常感谢任何帮助

此致

Apoorva

3 个答案:

答案 0 :(得分:0)

尝试增加执行程序核心。在您的示例中,唯一的核心专用于使用流数据,不会在传入数据中处理核心。

答案 1 :(得分:0)

这可能是内存泄漏...您是否尝试过conf.set(" spark.executor.extraJavaOptions"," -XX:+ UseG1GC")?

答案 2 :(得分:0)

这不是Kafka的答案,这将与Spark隔离,并且在涉及到持续的持久性和大型操作时,其编录系统也很差。如果您一直在写入周边点层(即在执行大型操作后在循环中重新存储DF,然后再次运行)或运行大型查询(即inputDF.distinct.count); Spark作业将开始将一些数据放入内存中,而不会有效地删除陈旧的对象。

这意味着可以快速运行一次的对象超时运行,它将稳定地减慢速度,直到没有可用的内存为止。对于在家中的每个人来说,在环境中加载有大型DataFrame的AWS EMR都可以运行以下查询:

var iterator = 1
val endState = 15
var currentCount = 0
while (iterator <= endState) {
  currentCount = inputDF.distinct.count
  print("The number of unique records are : " + currentCount)
  iterator = iterator + 1
}

在作业正在运行时,请监视Spark UI的内存管理,如果DF足够用于会话,那么随后的每次运行都会发现运行时间减少,主要是块变得陈旧,但是Spark无法确定何时清洁那些块。

找到此问题的最佳方法是在本地编写DF,清除持久层,然后将数据加载回去。这是解决问题的“大锤”方法,但对于我的业务案例这是一种易于实施的解决方案,它使大型表的运行时间增加了90%(将540分钟减少到40分钟左右,而内存较少)。

我当前使用的代码是:

val interimDF = inputDF.action
val tempDF = interimDF.write.format(...).option("...","...").save("...")
spark.catalog.clearCache
val interimDF = spark.read..format(...).option("...","...").save("...").persist
interimDF.count

如果您不在子子流程中取消持久化DF,则为派生形式:

val interimDF = inputDF.action
val tempDF = interimDF.write.format(...).option("...","...").save("...")
for ((k,v) <- sc.getPersistentRDDs) {
  v.unpersist()
}
val interimDF = spark.read..format(...).option("...","...").save("...").persist
interimDF.count