在使用抑制对KTable进行速率限制更新时有意丢弃状态

时间:2019-12-04 14:50:52

标签: apache-kafka-streams

我正在使用Kafka Streams 2.3.1 Prevent()运算符来限制发送到基础KTable的更新数量。

这里的用例是,在我的处理逻辑中,我想进行一次HTTP调用,但是为了限制调用次数,我正在对流进行窗口化并汇总属于同一时间窗口的源主题消息以进行单个API调用。

代码大致如下

KTable<Windowed<String>, List<Event>> windowedEventKTable = inputKStream
    .groupByKey()
    .windowedBy(TimeWindows.of(Duration.ofSeconds(30)).grace(Duration.ofSeconds(5))
    .aggregate(Aggregator::new, ((key, value, aggregate) -> aggregate.aggregate(value)), stateStore)
    .suppress(Suppressed.untilTimeLimit(Duration.ofSeconds(5), maxRecords(500).emitEarlyWhenFull())
    .mapValues((windowedKey, groupedTriggerAggregator) -> {//code here returning a list})
    .toStream((k,v) -> k.key())
    .flatMapValues((readOnlyKey, value) -> value);

我遇到的问题是,当发出超出记录限制的窗口时,会保留状态。在某个时间点,单个时间窗口的状态会增长到多个MB,从而导致强制存储变更日志消息超过主题的max.message.bytes限制。对于我们的用例,一旦发出窗口,我们实际上并不在乎剩余状态,可以放心删除它。

当我们在多个团队之间共享Kafka群集时,运行群集的团队不愿将群集级别max.message.bytes属性增加到我们所需的10 MB以上。

除了使用transformValues实现逻辑外,我是否还有其他选择?如果没有,将来是否有任何Kafka Streams增强功能可以立即解决?

1 个答案:

答案 0 :(得分:0)

  

对于我们的用例,一旦发出窗口,我们实际上并不在乎剩余状态,可以放心删除它。

在这种情况下,您可以通过aggregation()参数Materialized.withRetentiontTime(...)将商店保留时间(默认为1天)设置为与指定的宽限期相同的值。

  

我遇到的问题是,当发出超出记录限制的窗口时,会保留状态。在某个时候,单个时间窗口的状态会增长为多个MB,从而导致强制存储变更日志消息超过主题的最大消息数字节限制。

这实际上是一个有趣的语句,在查看您的代码时,我只想澄清一下:由于您受时间限制并允许根据缓存大小提前发出,因此您似乎有很多记录在外甚至在发出中间结果后也可以更新状态。如果如上所述通过保留时间清除状态,则需要考虑以下事项:

  • 清除状态不会影响基于缓存大小触发的任何发射,因为,仅在保留时间过去之后,该状态才会被清除。 0此外,清除状态表示清除后将完全不对清除后出现的所有乱序记录进行处理,但会丢弃(因为保留时间将带有较小时间戳的输入记录隐式地标记为“迟到”)。 。

但是,总的来说,您似乎并不真正在意乱序的数据和事件时间窗口,因为您可以“任意”将记录放入窗口中,因为唯一的目标是减少外部数据的数量API调用。因此,您似乎实际上可以通过使用WallclockTimetampExtractor(而不是默认提取器)来切换处理时间语义。为了确保每个记录仅发出一次,您应该更改suppress()配置以仅发出“最终”结果。