我目前正在开发一个Spark(v 2.2.0)Streaming应用程序,并且遇到了Spark似乎在整个群集中分配工作的问题。此应用程序使用客户端模式提交给AWS EMR,因此有一个驱动程序节点和几个工作节点。以下是Ganglia的屏幕截图,显示了过去一小时的内存使用情况:
最左边的节点是“主”或“驱动程序”节点,另外两个节点是工作节点。对于通过流进入的工作负载,所有三个节点的内存使用量都出现峰值,但峰值不相等(即使缩放到%内存使用量)。当大型工作负载进入时,驱动程序节点似乎过度工作,作业将因内存错误而崩溃:
OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x000000053e980000, 674234368, 0) failed; error='Cannot allocate memory' (errno=12)
我也碰到了这个: {<1}}当主内存不足时,同样令人困惑,因为我的理解是“客户端”模式不会将驱动程序/主节点用作执行程序。
相关细节:
Exception in thread "streaming-job-executor-10" java.lang.OutOfMemoryError: Java heap space
。spark-submit --deploy-mode client --master yarn ...
或collect
coalesce
主要读取)在完成后都是jdbc
。repartition
。我当然不知所措。我不确定代码中发生了什么事情会导致驱动程序像这样占用工作负载。
我能想到的唯一一个嫌疑人是类似于以下内容的代码片段:
persist
这里,从静态对象加载一个函数,用于映射 val scoringAlgorithm = HelperFunctions.scoring(_: Row, batchTime)
val rawScored = dataToScore.map(scoringAlgorithm)
。据我所知,Spark将在整个集群中序列化此功能(re:http://spark.apache.org/docs/2.2.0/rdd-programming-guide.html#passing-functions-to-spark)。不过也许我错了,它只是在驱动程序上运行这个转换。
如果有人对此问题有任何见解,我很乐意听到它!
答案 0 :(得分:0)
我最终解决了这个问题。以下是我如何解决它:
我在陈述问题时做了一个不正确的断言:在Spark程序的开头有一个collect
语句。
我的交易需要collect()
按照设计运行。我的假设是,对结果数据调用repartition(n)
会将数据拆分回集群中的执行程序。据我所知,这个策略不起作用。一旦我重新编写了这一行,Spark就开始按照我的预期行事,并将工作岗位转移到工作节点。
我对任何在这个问题上遇到困难的失去灵魂的建议:不要collect
,除非这是你的Spark程序的结束。你无法从它恢复。找到另一种方法来执行您的任务。 (我最终将SQL事务从where col in (,,,)
语法切换到数据库上的连接。)