Apache kafka Kafka在窗口打开和重新启动时对丢弃的消息进行流式处理
我正在使用以下拓扑结构开发Kafka Streams应用程序:Apache kafka Kafka在窗口打开和重新启动时对丢弃的消息进行流式处理,apache-kafka,apache-kafka-streams,windowing,Apache Kafka,Apache Kafka Streams,Windowing,我正在使用以下拓扑结构开发Kafka Streams应用程序: private final Initializer<Set<String>> eventInitializer = () -> new HashSet<>(); final StreamsBuilder streamBuilder = new StreamsBuilder(); final KStream<String, AggQuantityByPrimeValue>
private final Initializer<Set<String>> eventInitializer = () -> new HashSet<>();
final StreamsBuilder streamBuilder = new StreamsBuilder();
final KStream<String, AggQuantityByPrimeValue> eventStreams = streamBuilder.stream("testTopic",
Consumed.with(Serdes.String(), **valueSerde**));
final KStream<String, Value> filteredStreams = eventStreams
.filter((key,clientRecord)->recordValidator.isAllowedByRules(clientRecord));
final KGroupedStream<Integer, Value> groupedStreams = filteredStreams.groupBy(
(key, transactionEntry) -> transactionEntry.getNodeid(),
Serialized.with(Serdes.Integer(), **valueSerde**));
/* Hopping window */
final TimeWindowedKStream<Integer, Value> windowedGroupStreams = groupedStreams
.windowedBy(TimeWindows.of(Duration.ofSeconds(30)).advanceBy(Duration.ofSeconds(25))
.grace(Duration.ofSeconds(0)));
/* Aggregating the events */
final KStream<Windowed<Integer>, Set<String>> suppressedStreams = windowedGroupStreams
.aggregate(eventInitializer, countAggregator, Materialized.as("counts-aggregate")
.suppress(Suppressed.untilWindowCloses(Suppressed.BufferConfig.unbounded())
.withName("suppress-window")
.toStream();
suppressedStreams.foreach((windowed, value) -> eventProcessor.publish(windowed.key(), value));
return new KafkaStreams(streamBuilder.build(), config.getKafkaConfigForStreams());
private final Initializer eventInitializer=()->new HashSet();
最终StreamsBuilder streamBuilder=新StreamsBuilder();
最终KStream eventStreams=streamBuilder.stream(“testTopic”,
使用(Serdes.String(),**valueSerde**));
最终KStream filteredStreams=事件流
.filter((键,clientRecord)->recordValidator.isAllowedByRules(clientRecord));
最终KGroupedStream groupedStreams=filteredStreams.groupBy(
(键,transactionEntry)->transactionEntry.getNodeid(),
序列化的.with(Serdes.Integer(),**valueSerde**));
/*跳窗*/
最终时间WindowedKStream windowedGroupStreams=groupedStreams
.windowedBy(TimeWindows.of(持续时间秒(30)).advanceBy(持续时间秒(25))
.grace(持续时间为秒(0));
/*聚合事件*/
最终KStream suppressedStreams=windowedGroupStreams
.aggregate(eventInitializer、countAggregator、Materialized.as(“counts aggregate”)
.suppress(supprested.untilwindowcloss(supprested.BufferConfig.unbounded())
.withName(“抑制窗口”)
.toStream();
suppressedStreams.foreach((加窗,值)->eventProcessor.publish(加窗,键(),值));
返回新的KafkaStreams(streamBuilder.build(),config.getkafkanconfigforstreams());
我观察到,在窗口打开期间/之后,间歇性地很少有事件被丢弃。
例如:
- 所有记录都可以在isAllowedByRules()方法中查看/打印,这些记录都是有效的(过滤器允许的)并由流使用
- 但是当在countAggregator中打印事件时,我可以看到很少有事件没有通过它
Properties streamsConfig = new Properties();
streamsConfig.put(StreamsConfig.APPLICATION_ID_CONFIG,"kafka-app-id"
streamsConfig.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, <bootstraps-server>);
streamsConfig.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");
streamsConfig.put(StreamsConfig.COMMIT_INTERVAL_MS_CONFIG, 30000);
streamsConfig.put(StreamsConfig.NUM_STREAM_THREADS_CONFIG, 5);
streamsConfig.put(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG, 10000);
streamsConfig.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, 30000);
streamsConfig.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG, 10485760);
streamsConfig.put(ProducerConfig.MAX_REQUEST_SIZE_CONFIG, 10485760);
streamsConfig.put(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, 10485760);
/*For window buffering across all threads*/
streamsConfig.put(StreamsConfig.CACHE_MAX_BYTES_BUFFERING_CONFIG, 52428800);
streamsConfig.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.Integer().getClass().getName());
streamsConfig.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, **customSerdesForSet**);
Properties streamsConfig=新属性();
streamsConfig.put(streamsConfig.APPLICATION\u ID\u CONFIG,“卡夫卡应用程序ID”
streamsConfig.put(streamsConfig.BOOTSTRAP_SERVERS_CONFIG,);
streamsConfig.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,“最新”);
streamsConfig.put(streamsConfig.COMMIT\u INTERVAL\u MS\u CONFIG,30000);
streamsConfig.put(streamsConfig.NUM\u STREAM\u THREADS\u CONFIG,5);
streamsConfig.put(ConsumerConfig.HEARTBEAT\u INTERVAL\u MS\u CONFIG,10000);
streamsConfig.put(ConsumerConfig.SESSION\u TIMEOUT\u MS\u CONFIG,30000);
streamsConfig.put(ConsumerConfig.FETCH\u MAX\u BYTES\u CONFIG,10485760);
streamsConfig.put(ProducerConfig.MAX\u REQUEST\u SIZE\u CONFIG,10485760);
streamsConfig.put(ConsumerConfig.MAX\u PARTITION\u FETCH\u BYTES\u CONFIG,10485760);
/*用于跨所有线程的窗口缓冲*/
streamsConfig.put(streamsConfig.CACHE\u MAX\u BYTES\u BUFFERING\u CONFIG,52428800);
streamsConfig.put(streamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG,Serdes.Integer().getClass().getName());
streamsConfig.put(streamsConfig.DEFAULT\u VALUE\u SERDE\u CLASS\u CONFIG,**customSerdesForSet**);
最初,我使用的是翻滚窗口,但我发现大多数情况下在窗口结束时,很少有事件丢失,所以我改为跳跃窗口(复制比丢失更好)。然后丢弃的事件变为零。但今天,在将近4天之后,我又看到了一些丢弃的事件,其中有一种模式,即与一起生成的其他事件相比,它们迟到了近一分钟。但预期这些迟到的事件会出现在未来的任何窗口中,但不会发生。对吗如果我的理解不正确的话
正如我在主题中提到的,在重新启动流时(优雅地),我可以看到在聚合步骤中很少有事件再次丢失,尽管是通过isAllowedByRules()方法处理的
我在堆栈溢出和其他站点上搜索了很多,但找不到这种行为的根本原因。这是否与我缺少/未正确设置的某些配置有关,或者可能是由于其他原因造成的?据我所知,您的宽限期为空:
/* Hopping window */
...
.grace(Duration.ofSeconds(0))
所以你的窗口是关闭的,不允许任何迟到的人
那么关于你的子问题:
但人们期望这些迟来的事件会出现在未来的任何窗口中,但不会发生。如果我的理解不正确,请在此处更正。
也许你把事件时间和处理时间混在一起了。
如果记录的时间戳(由制作人在制作时添加,或由代理在到达集群时添加,如果不是由制作人设置),则您的记录将被归类为“延迟”
下面是一个包含2条记录“*”的示例
他们的活动时间(et1和et2)适合窗口:
| window |
t1 t2
| * * |
et1 et2
但是,et2(pt2)的处理时间实际上如下:
| window |
t1 t2
| * | *
pt1 pt2
这里的窗口是t1和t2之间的一段时间(处理时间)
et1和et2分别是2条记录“*”的事件时间。
et1和et2是在记录本身中设置的时间戳。
在本例中,et1和et2介于t1和t2之间,et2在窗口关闭后已收到,由于宽限期为0,因此将跳过
可能是一种解释transactionEntry.getNodeid()可能会返回null(从而解释某些删除)?
但预期这些延迟事件会出现在未来的任何窗口中,但不会发生
——正如下面@Yannick的回答中所提到的,这在默认情况下不会发生,因为默认情况下使用了事件时间语义。可能会将时间戳。提取器
更改为WallclockTimestampExtractor
解决您的问题。Hi@MatthiasJ.Sax stream谢谢您的回复。它运行了很长一段时间,但我再次看到邮件被删除。在您的建议后,我将时间戳。提取器
更改为WallclockTimestampExtractor
。此外,我还添加了宽限期。当前配置为:Kafka窗口时间:30秒窗口提前时间:25秒宽限期:60秒提交间隔:100秒是否可能