Apache kafka 卡夫卡流拓扑与窗口不';t触发状态变化
我正在构建以下Kafka Streams拓扑(伪代码): 如果您注意到,这是一个类似菱形的拓扑,从单个输入主题开始,到单个输出主题结束,消息通过两个并行流流动,最终在最后连接在一起。一个流应用(翻滚?)窗口,另一个不应用。流的两个部分在同一个键上工作(除了窗口化中间引入的WindowedKey) 我的消息的时间戳是事件时间。也就是说,它们由我的自定义配置的Apache kafka 卡夫卡流拓扑与窗口不';t触发状态变化,apache-kafka,apache-kafka-streams,Apache Kafka,Apache Kafka Streams,我正在构建以下Kafka Streams拓扑(伪代码): 如果您注意到,这是一个类似菱形的拓扑,从单个输入主题开始,到单个输出主题结束,消息通过两个并行流流动,最终在最后连接在一起。一个流应用(翻滚?)窗口,另一个不应用。流的两个部分在同一个键上工作(除了窗口化中间引入的WindowedKey) 我的消息的时间戳是事件时间。也就是说,它们由我的自定义配置的TimestampExtractor实现从消息体中拾取。我的消息中的实际时间戳是几年前的事了 这一切在我的单元测试中(使用两条输入/输出消息)
TimestampExtractor
实现从消息体中拾取。我的消息中的实际时间戳是几年前的事了
这一切在我的单元测试中(使用两条输入/输出消息)和运行时环境中(使用真正的Kafka)一目了然,效果都很好
当消息数量开始显著时(例如40K),问题似乎就出现了
我失败的情况如下:
TopologyTestDriver
本地(但仅在大量输入记录上)轻松地重现这个问题
在我的测试中,我尝试使用StreamsConfig.CACHE\u MAX\u BYTES\u BUFFERING\u CONFIG
禁用缓存。不幸的是,这没有任何区别
更新
我同时尝试了reduce()调用和aggregate()调用。这一问题在这两种情况下都存在
我还注意到,如果将StreamsConfig.TOPOLOGY\u OPTIMIZATION
设置为StreamsConfig.OPTIMIZE
,则至少第一次在前面的reduce()(或aggregate())处理程序之前在调试器中调用mapValues()处理程序。我没想到
尝试了join()和leftJoin(),但结果相同。
在调试器中,数据的第二部分根本不会在“左”流中触发reduce()处理程序,而是在“右”流中触发reduce()处理程序
在我的配置中,如果两个数据集中的记录数都是100,则问题不会自行显现,我将获得200条预期的输出消息。当我将每个数据集中的数字提高到200时,我得到的预期消息不到400条。
因此,目前似乎“旧”窗口之类的内容被删除,而流忽略了这些旧窗口的新记录。
有一个可以设置的窗口保留设置,但使用它的默认值,我希望windows保持其状态并保持活动状态至少12小时(大大超过我的单元测试运行时间)
尝试使用以下窗口存储配置修改左减速器:
Materialized.as(
Stores.inMemoryWindowStore(
"rollup-left-reduce",
Duration.ofDays(5 * 365),
Duration.ofHours(1), false)
)
结果仍然没有差别
即使只有一个“左”流而没有“右”流且没有join(),同样的问题仍然存在。问题似乎出在我的设置的窗口保留设置中。我的输入记录的时间戳(事件时间)跨度为2年。第二个数据集再次从两年开始。Kafka Streams中的此位置确保忽略第二个数据集记录:
卡夫卡流版本是2.4.0。还使用汇合依赖项版本5.4.0
我的问题是
- 这种行为的原因可能是什么
- 我的流拓扑中是否遗漏了任何内容
- 这样的拓扑结构会起作用吗李>
- 经过一段调试时间后,我找到了问题的原因
我的输入数据集包含时间戳为2年的记录。我正在加载第一个数据集,然后将流的“观察”时间设置为输入数据集的最大时间戳
上载第二个数据集,该数据集以时间戳早于新观测时间2年的记录开始,导致内部流丢弃消息。如果将Kafka日志设置为跟踪级别,则可以看到这一点
因此,为了解决我的问题,我必须为我的windows配置保留期和宽限期:
而不是
我必须具体说明.windowedBy(TimeWindows.of(windowSize))
此外,我还必须明确地将reducer存储设置配置为:.windowedBy(TimeWindows.of(windowSize).grace(Duration.ofDays(5 * 365)))
Materialized.as( Stores.inMemoryWindowStore( "rollup-left-reduce", Duration.ofDays(5 * 365), windowSize, false) )
就是这样,输出正如预期的那样。这是一个非常有趣的问题,您能否以某种方式与生成的测试共享代码谢谢您的关注,@TuyenLuong。我会更新后一点与更多的细节。目前,我怀疑原因在于join()部分。似乎该片段可能会陷入竞争状态,因此在一个流中传输的消息无法及时从另一个流中获得对应的消息。可能是记录缓存造成了问题?使用
可以禁用它--您可以尝试设置TopologyTestDriver
来禁用缓存吗?(cf:)谢谢@MatthiasJ.Sax,我一开始就这么做了(在描述中也提到了)很好的发现!我以为你在处理新数据之前先处理了旧数据。对于在旧数据之前处理新数据,这完全有道理:)cache.max.bytes.buffering=0
Materialized.as( Stores.inMemoryWindowStore( "rollup-left-reduce", Duration.ofDays(5 * 365), windowSize, false) )