我希望将来自KStream的窗口批输出组合在一起并将它们写入辅助存储。
我希望大约每30秒看一次.punctuate()
。我得到的是保存here。
(原始文件长达数千行)
摘要 - .punctuate()
似乎随机而且反复调用。它似乎不符合ProcessorContext.schedule()设置的值。
同一代码的另一次运行大约每四分钟产生一次.punctuate()
的调用。这次我没有看到疯狂的重复值。来源没有变化 - 只是结果不同。
使用以下代码:
StreamsConfig streamsConfig = new StreamsConfig(config);
KStreamBuilder kStreamBuilder = new KStreamBuilder();
KStream<String, String> lines = kStreamBuilder.stream(TOPIC);
lines.process(new BPS2());
KafkaStreams kafkaStreams = new KafkaStreams(kStreamBuilder, streamsConfig);
kafkaStreams.start();
public class BP2 extends AbstractProcessor<String, String> {
private static final Logger LOGGER = LoggerFactory.getLogger(BP2.class);
private ProcessorContext context;
private final long delay;
private final ArrayList<String> values;
public BP2(long delay) {
LOGGER.debug("BatchProcessor() constructor");
this.delay = delay;
values = new ArrayList<>();
}
@Override
public void process(String s, String s2) {
LOGGER.debug("batched processor s:{} s2:{}", s, s2);
values.add(s2);
}
@Override
public void init(ProcessorContext context) {
LOGGER.info("init");
super.init(context);
values.clear();
this.context = context;
context.schedule(delay);
}
@Override
public void punctuate(long timestamp) {
super.punctuate(timestamp);
LOGGER.info("punctuate ts: {} count: {}", timestamp, values.size());
context().commit();
}
}
public class BPS2 implements ProcessorSupplier<String, String> {
private static final Logger LOGGER = LoggerFactory.getLogger(BPS2.class);
@Override
public Processor<String, String> get() {
try {
return new BP2(30000);
} catch(Exception exception) {
LOGGER.error("Unable to instantiate BatchProcessor()", exception);
throw new RuntimeException();
}
}
}
为了确保我的调试器没有减慢速度,我构建它并在与我的kafka进程相同的盒子上运行它。这次它甚至没有试图延迟4分钟或更长时间 - 在几秒钟内就输出了对.punctuate()
的虚假来电。其中许多(大多数)没有对.process()
进行干预。
答案 0 :(得分:6)
更新:这部分答案适用于Kafka 0.11版或更早版本(适用于Kafka 1.0及更高版本,见下文)
在Kafka Streams中,标点符号基于流时和不 系统时间(又称处理时间)。
默认流时是事件时间,即Kafka记录中嵌入的时间戳。由于您未设置非默认TimestampExtractor
(请参阅http://docs.confluent.io/current/streams/developer-guide.html#optional-configuration-parameters中的timestamp.extractor
),因此对punctuate
的调用仅取决于事件时间与您处理的记录。因此,如果你需要多分钟来处理&#34; 30秒&#34; (事件时间)记录,punctuate
的频率低于30秒(挂钟时间)......
这也可以解释您的不规则呼叫模式(即突发和长延迟)。如果您的数据事件时间为&#34;跳转&#34;,并且您的主题中已经完全提供了您要处理的数据,那么Kafka Streams也会跳过&#34;跳跃&#34;关于内部维护流时间。
我认为您可以使用WallclockTimestampExtractor
解决问题(请参阅http://docs.confluent.io/current/streams/developer-guide.html#timestamp-extractor)
还有一件事要提到:流时间仅在处理数据时才会提前 - 如果您的应用程序到达输入主题的末尾并等待数据,punctuate
将不会叫做。即使您使用WallclockTimestampExtractor
,这也适用。
回答Kafka 1.0及更高版本
从Kafka 1.0开始,可以根据挂钟时间或事件时间注册标点符号:https://kafka.apache.org/10/documentation/streams/developer-guide/processor-api.html#id2
答案 1 :(得分:0)
刚读完this question的答案,我认为这也是你的答案。它的要点是:
指出标点符号不是一个固定的时间间隔事件,#2所用时间的变化将导致标点执行周期的等效变化。
....但是读了那个链接,他说它比我好。
答案 2 :(得分:0)
好的 - 我认为这是卡夫卡的一个错误。
这就是原因:
在我原来的测试中,我使用一台机器来运行 Producer 和 Consumer 。我会运行Producer几分钟来生成一些测试数据,然后运行我的测试。这会给出我最初发布的奇怪输出。
然后我决定将Producer推到后台并让它继续运行。现在,在.punctuate()
的调用之间,我看到100%完美的30秒间隔。没有更多的问题。
换句话说 - 如果kafka服务器没有处理任何入站数据,那么它似乎与运行 KStreams 进程一致。