Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache kafka 卡夫卡流拓扑与窗口不';t触发状态变化_Apache Kafka_Apache Kafka Streams - Fatal编程技术网

Apache kafka 卡夫卡流拓扑与窗口不';t触发状态变化

Apache kafka 卡夫卡流拓扑与窗口不';t触发状态变化,apache-kafka,apache-kafka-streams,Apache Kafka,Apache Kafka Streams,我正在构建以下Kafka Streams拓扑(伪代码): 如果您注意到,这是一个类似菱形的拓扑,从单个输入主题开始,到单个输出主题结束,消息通过两个并行流流动,最终在最后连接在一起。一个流应用(翻滚?)窗口,另一个不应用。流的两个部分在同一个键上工作(除了窗口化中间引入的WindowedKey) 我的消息的时间戳是事件时间。也就是说,它们由我的自定义配置的TimestampExtractor实现从消息体中拾取。我的消息中的实际时间戳是几年前的事了 这一切在我的单元测试中(使用两条输入/输出消息)

我正在构建以下Kafka Streams拓扑(伪代码):

如果您注意到,这是一个类似菱形的拓扑,从单个输入主题开始,到单个输出主题结束,消息通过两个并行流流动,最终在最后连接在一起。一个流应用(翻滚?)窗口,另一个不应用。流的两个部分在同一个键上工作(除了窗口化中间引入的WindowedKey)

我的消息的时间戳是事件时间。也就是说,它们由我的自定义配置的
TimestampExtractor
实现从消息体中拾取。我的消息中的实际时间戳是几年前的事了

这一切在我的单元测试中(使用两条输入/输出消息)和运行时环境中(使用真正的Kafka)一目了然,效果都很好

当消息数量开始显著时(例如40K),问题似乎就出现了

我失败的情况如下:

  • 约有4万张记录与此相同 键首先上传到输入主题中

  • 大约有4万次更新 正如预期的那样,从输出主题出来

  • 另约4万张唱片 使用与步骤1)相同但不同的密钥上传到 输入主题

  • 输出主题中只有约100个更新, 而不是预期的新的~40K更新。没有什么特别的 在那100次更新中,他们的内容似乎是正确的,但是 只有特定的时间窗口。对于其他时间窗口,没有 更新,即使流逻辑和输入数据应该明确 生成4万条记录。事实上,当我在步骤1中交换数据集时) 3)我有完全相同的情况,大约有40K个更新来自 第二个数据集与第一个数据集的编号相同~100

  • 我可以在单元测试中使用
    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))
        
        我必须具体说明

        .windowedBy(TimeWindows.of(windowSize).grace(Duration.ofDays(5 * 365)))
        
        此外,我还必须明确地将reducer存储设置配置为:

         Materialized.as(
            Stores.inMemoryWindowStore(
                "rollup-left-reduce",
                Duration.ofDays(5 * 365),
                windowSize, false)
        )
        

        就是这样,输出正如预期的那样。

        这是一个非常有趣的问题,您能否以某种方式与生成的测试共享代码谢谢您的关注,@TuyenLuong。我会更新后一点与更多的细节。目前,我怀疑原因在于join()部分。似乎该片段可能会陷入竞争状态,因此在一个流中传输的消息无法及时从另一个流中获得对应的消息。可能是记录缓存造成了问题?使用
        TopologyTestDriver
        可以禁用它--您可以尝试设置
        cache.max.bytes.buffering=0
        来禁用缓存吗?(cf:)谢谢@MatthiasJ.Sax,我一开始就这么做了(在描述中也提到了)很好的发现!我以为你在处理新数据之前先处理了旧数据。对于在旧数据之前处理新数据,这完全有道理:)
         Materialized.as(
            Stores.inMemoryWindowStore(
                "rollup-left-reduce",
                Duration.ofDays(5 * 365),
                windowSize, false)
        )