Kafka流聚合:如何忽略窗口的中间聚合结果

时间:2018-07-12 05:50:49

标签: java apache-kafka-streams

我们在时间窗口中使用kafka-stream聚合来计算事件的结束总和。我们已经实现了我们的要求,但是中间汇总结果存在问题。根据Kafka内存管理文档(https://kafka.apache.org/11/documentation/streams/developer-guide/memory-mgmt.html),似乎没有办法丢弃影响最终结果的中间结果。请考虑以下说明,该说明取自上述文档。

  

使用以下示例了解有无行为   记录缓存。在此示例中,输入是带有记录KStream<String,Integer>的{​​{1}}。   在此示例中,重点是使用<K,V>: <A, 1>, <D, 5>, <A, 20>, <A, 300>的记录。

     

聚合计算记录值的总和,按键分组   输入并返回一个key == A

     

无缓存:为密钥A发出一系列输出记录   代表结果汇总表中的更改。的   括号(())表示更改,左边的数字是新的聚合   值,正确的数字是旧的合计值:   KTable<String, Integer>

     

具有缓存::为密钥A发出一条输出记录,该记录将   可能会在缓存中进行压缩,从而导致单个输出记录   <A, (1, null)>, <A, (21, 1)>, <A, (321, 21)>。将此记录写入汇总的   内部状态存储并转发给任何下游操作。

     

通过<A, (321, null)>指定缓存大小   参数,它是每个处理拓扑的全局设置:

根据文档,在不缓存输出记录的情况下使用聚合会产生增量结果。 (我们注意到即使使用缓存有时也会发生这种情况)。我们的问题是我们还有其他应用程序对这些输出聚合起作用并进行一些计算。因此,当输出具有中间聚合时,这些其他计算将出错。例如,当发生cache.max.bytes.buffering事件时,我们可能会开始计算其他内容(应该在该时间窗口的<A (21,1)>上进行正确的计算。

我们的要求是仅对该窗口上的最终聚合进行其他计算。关于kafka流聚合,我们有以下问题

  1. 当kakfa输出中间结果时,这些输出是否已经聚合了数据?例如,考虑输出<A (321, null)>。此处<A, (1, null)>, <A, (21, 1)>, <A, (321, 21)>的第二个输出事件是,而第三个输出<A, (21, 1)>的值已经聚合。这是正确的吗?
  2. 有没有办法确定窗口的中间结果?

2 个答案:

答案 0 :(得分:3)

要记住的另一件事是提交时间间隔 ,缓存大小决定何时将结果转发到下游。

例如,如果您的提交间隔为10秒,则意味着无论缓存是否已满,都将转发缓存中的结果(并在启用日志记录的情况下将其写入changelog主题)。

因此,如果您可以将内存设置得足够高以支持将提交间隔设置为所需的窗口时间,则可以近似得出一个最终结果。当然,这是一种粗粒度方法,会影响整个拓扑,因此您需要考虑并可能为示例应用程序创建原型,以查看该方法是否适合您。

答案 1 :(得分:0)

我想你想要的是窗口的最终结果。因此,您可以抑制结果,以便仅发布最终结果。

这是一个抑制最终结果的例子:

KGroupedStream<UserId, Event> grouped = ...;
grouped
    .windowedBy(TimeWindows.of(Duration.ofHours(1)).grace(ofMinutes(10)))
    .count()
    .suppress(Suppressed.untilWindowCloses(unbounded()))
    .filter((windowedUserId, count) -> count < 3)
    .toStream()
    .foreach((windowedUserId, count) -> sendAlert(windowedUserId.window(), windowedUserId.key(), count));    

如您所见,suppress(Suppressed.untilWindowCloses(unbounded())) 可以解决问题。