Kafka KStream - 使用带窗口的AbstractProcessor

时间:2016-08-31 14:11:15

标签: java apache-kafka apache-kafka-streams

我希望将来自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();
    }
}

ProcessorSupplier

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()进行干预。

3 个答案:

答案 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,这也适用。

Btw:目前有关于Streams标点符号行为的讨论:https://github.com/apache/kafka/pull/1689

回答Kafka 1.0及更高版本

从Kafka 1.0开始,可以根据挂钟时间或事件时间注册标点符号:https://kafka.apache.org/10/documentation/streams/developer-guide/processor-api.html#id2

答案 1 :(得分:0)

刚读完this question的答案,我认为这也是你的答案。它的要点是:

  1. 流消费者对记录执行投票
  2. 完全处理所有返回的记录。
  3. 然后使用配置的延迟安排标点符号回调。
  4. 指出标点符号不是一个固定的时间间隔事件,#2所用时间的变化将导致标点执行周期的等效变化。

    ....但是读了那个链接,他说它比我好。

答案 2 :(得分:0)

好的 - 我认为这是卡夫卡的一个错误。

这就是原因:

在我原来的测试中,我使用一台机器来运行 Producer Consumer 。我会运行Producer几分钟来生成一些测试数据,然后运行我的测试。这会给出我最初发布的奇怪输出。

然后我决定将Producer推到后台并让它继续运行。现在,在.punctuate()的调用之间,我看到100%完美的30秒间隔。没有更多的问题。

换句话说 - 如果kafka服务器没有处理任何入站数据,那么它似乎与运行 KStreams 进程一致。