我使用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分钟的时间内保存消息。
据我了解,缓冲区应该被刷新,因此只有最后一分钟会消耗内存-所有其他窗口都应该被清除。
我做错什么了吗?
将寻求任何帮助。
答案 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的建议,只是为了更加安全(谢谢)。