Kafka Streams的“抑制”功能导致OOM / GC过多

时间:2019-12-08 20:50:48

标签: apache-kafka apache-kafka-streams

我使用Kafka Streams 2.1,并使用“抑制”功能创建了以下流,以处理每分钟的汇总:

originStream
    .windowedBy(TimeWindows.of(Duration.ofSeconds(60)).grace(Duration.ofMillis(500)))
    .aggregate(factory::createAggregation,
        (k, v, a) -> a.aggregate(v),
        materialized.withLoggingDisabled())
    .suppress(untilWindowCloses(Suppressed.BufferConfig.unbounded()))
    .toStream();

我收到的邮件速率约为每秒200条。 片刻之后,我看到GC开始非常努力地工作,有时出现OOM错误。

由于我使用的是2GB的堆,而一条记录占用的空间不会超过1KB,所以对我来说很明显,这是有问题的-在1分钟的窗口中爆炸2GB的堆不应有太多消息。

所以..我进行了一个堆转储,在其中我看到5个InMemoryTimeOrderedKeyValueBuffer对象,每个对象占用300MB以上(总计> 1.5GB)。

我深入其中之一,发现在sortedMap中最小/最高的时间戳是1,575,458,160,000 / 1,575,481,800,000。这意味着缓冲区在23,640,000 = 394分钟的时间内保存消息。

据我了解,缓冲区应该被刷新,因此只有最后一分钟会消耗内存-所有其他窗口都应该被清除。

我做错什么了吗?

将寻求任何帮助。

2 个答案:

答案 0 :(得分:1)

问题不应该是suppress(),而应该是聚合状态存储。默认情况下,其保留时间为1天。您可以通过将Materialized.withRetention(...)传递到aggregate()中来减少保留时间。

我很惊讶您的堆转储显示InMemoryTimeOrderedKeyValueBuffer,因为这是suppress()使用的存储。因此,我不确定100%减少保留时间是否可以解决此问题。

顺便说一句:2.1中的suppress()中有一些错误仅在2.3版本中得到修复,因此强烈建议您使用suppress()升级到2.3。

答案 1 :(得分:0)

我将BufferConfig更改为使用最大字节边界:

Suppressed.BufferConfig.unbounded().withMaxBytes(10_000_000)

这似乎可以解决问题。我看了一下代码,却不明白为什么-因为我现在看到它应该抛出一个异常,但是没有。

因此,我在这里仍然不了解某些内容,但问题已解决。

此后,我也使用了Mattias J. Sax的建议,只是为了更加安全(谢谢)。