【问题标题】:Trident Topology throws out of memory exception三叉戟拓扑抛出内存不足异常
【发布时间】:2015-04-14 10:50:14
【问题描述】:

我正在从 Storm 的传统拓扑转移到 Trident 拓扑,后者在将元组推送到数据库之前维护成批的元组。我们将 XML 处理为单个元组。在一次处理一个 xml 的传统拓扑中,这很好用。但是在 Trident 拓扑中,在提交到数据库之前,它会在内存中保留大量元组,这会导致内存不足异常。也不清楚风暴如何决定批量大小以及它在每次迭代中的变化。以下是我们收到的错误:

java.lang.OutOfMemoryError:java.lang.AbstractStringBuilder 的 java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130) 的 java.util.Arrays.copyOf(Arrays.java:2367) 超出了 GC 开销限制。 ensureCapacityInternal(AbstractStringBuilder.java:114) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:415) at java.lang.StringBuilder.append(StringBuilder.java:132) at clojure.core$str$fn__3896.invoke(core .clj:517) at clojure.core$str.doInvoke(core.clj:519) at clojure.lang.RestFn.invoke(RestFn.java:423) at backtype.storm.daemon.executor$mk_task_receiver$fn__5564.invoke( executor.clj:397) 在 backtype.storm.disruptor$clojure_handler$reify__745.onEvent(disruptor.clj:58) 在 backtype.storm.utils.DisruptorQueue.consumeBatchToCursor(DisruptorQueue.java:125) 在 backtype.storm.utils.DisruptorQueue .consumeBatchWhenAvailable(DisruptorQueue.java:99) at backtype.storm.disruptor$consume_batch_when_available.invoke(disruptor.clj:80) at backtype.storm.daemon.execut或 $fn__5641$fn__5653$fn__5700.invoke(executor.clj:746) at backtype.storm.util$async_loop$fn__457.invoke(util.clj:431) at clojure.lang.AFn.run(AFn.java:24)在 java.lang.Thread.run(Thread.java:745)

更多信息:

在处理螺栓时,我们使用 DOM 解析器来解析 XML。我们试图通过将 XML 的单个元素作为一个元组来减小单个元组的大小,但这也无济于事。

可能的解决方案可能包括限制存储在内存中的批次大小或采用快速垃圾收集。

【问题讨论】:

  • 垃圾收集器的问题很棘手。见this reference。您正在使用哪些内存选项?您可能可以稍微调整一些值,但无论如何,除非您的内存选项确实有问题,否则错误的原因必须与创建无法删除的内存对象负载有关......您使用的代码是您的吗?
  • 您应该能够使用 kafkaConfig 设置 bufferSizeBytes 和 fetchSizeBytes 来控制批量大小。见czcodezone.blogspot.com/2014/12/…
  • 考虑阅读tuning Storm+Trident

标签: xml out-of-memory apache-storm apache-kafka trident


【解决方案1】:

java.lang.OutOfMemoryError: GC 开销限制超出

以下是异常原因

详细信息“GC 开销限制超出”表示垃圾收集器一直在运行,Java 程序进展缓慢。垃圾回收后,如果 Java 进程花费超过大约 98% 的时间进行垃圾回收,并且如果它回收的堆少于 2%,并且到目前为止一直在做最后 5 个(编译时间常数)连续垃圾集合,然后抛出 java.lang.OutOfMemoryError。通常会引发此异常,因为实时数据量几乎无法放入 Java 堆中,几乎没有用于新分配的可用空间。

详情请看这里

http://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/memleaks.html

此问题的真正原因是应用程序的内存使用量增加,并且 GC 无法清除应用程序继续工作可能需要的足够内存,因此在抛出 OOME(java.lang.OutOfMemoryError: Java 堆空间)JVM 吐了这个。我已经做了很多 JVM 的调优等工作,但从来没有看到过这条消息,因为我可能已经对旧版本的 JVM 进行了调优,但没有出现这条消息。

从逻辑上讲,有两种可能会看到此消息 - 应用程序正在泄漏内存。 - 应用程序正在消耗更多内存。

对于前一种情况,您需要修复内存泄漏,解决方法是分析堆转储并检查正在消耗内存的内容,确保不是泄漏。 heapdump可以用eclipse MAT分析,我个人用过。

对于后一种情况,您将不得不增加堆大小,这也在我上面粘贴的链接中进行了说明,您需要执行以下操作

操作:增加堆大小。超过 GC Overhead limit 的 java.lang.OutOfMemoryError 异常可以通过命令行标志 -XX:-UseGCOverheadLimit 关闭。

【讨论】:

    【解决方案2】:

    我可以通过如下设置 kafka fetch 大小和缓冲区大小来控制每次迭代中的批大小:

        spoutConf.fetchSizeBytes = 5*1024*1024;
        spoutConf.bufferSizeBytes = 5*1024*1024;
    

    这限制了保存在内存中的数据量。我们将不得不根据您的用例调整此限制,以便内存中的数据对于您的系统来说不会太大,但系统可以提供最大的吞吐量。

    【讨论】:

    • 对不起。你写道你使用了三叉戟,所以你怎么能为三叉戟设置喷口。三叉戟应该没有喷口螺栓吗?
    猜你喜欢
    • 2013-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多