产生主题时,Kafka Streams不会将偏移量增加1

时间:2019-02-11 18:03:37

标签: java apache-kafka kafka-consumer-api apache-kafka-streams kafka-producer-api

我已经实现了一个简单的Kafka Dead信记录处理器。

当使用由控制台生产者产生的记录时,它完美地工作。

但是我发现我们的Kafka Streams应用程序不能保证向接收器主题生成记录,即对于每条产生的记录,偏移量将增加1。

死信处理器背景:

我有一个方案,在发布处理记录所需的所有数据之前,可能会先接收记录。 当记录与流应用程序不匹配以进行处理时,它们将移至“死信”主题,而不是继续向下流。当发布新数据时,我们会将“死信”主题中的最新消息转储回流应用程序的源主题中,以使用新数据进行重新处理。

死信处理器:

  • 在运行应用程序的开始处,记录每个分区的结束偏移量
  • 结束偏移量标记为停止处理给定死信主题的记录的点,以避免在重新处理的记录返回死信主题时产生无限循环。
  • 应用程序从上次运行通过消费者组产生的最后偏移中恢复。
  • 应用程序正在使用事务,并且KafkaProducer#sendOffsetsToTransaction提交最后产生的偏移量。

要跟踪何时针对某个主题的分区处理了我范围内的所有记录,我的服务将其从生产者到生产者的最后产生的偏移量与消费者保存的结束偏移量图进行比较。当我们到达结束偏移时,使用者通过KafkaConsumer#pause暂停该分区,并且当所有分区都暂停时(这意味着它们已达到保存的结束偏移),然后调用它退出。

Kafka Consumer API状态:

  

抵销和消费者地位   Kafka维护分区中每个记录的数字偏移量。此偏移量充当该分区内记录的唯一标识符,并且还指示使用者在分区中的位置。例如,位置5的使用者使用了偏移量为0到4的记录,然后将接收偏移量为5的记录。

Kafka Producer API引用的下一个偏移量也总是+1。

  

将指定偏移量的列表发送给使用者组协调器,并将这些偏移量标记为当前事务的一部分。仅当事务成功提交后,这些偏移量才被视为已提交。提交的偏移量应该是您的应用程序将使用的下一条消息,即lastProcessedMessageOffset + 1。

但是您可以在我的调试器中清楚地看到,单个分区消耗的记录一次几乎不会增加1 ... enter image description here

我以为这可能是Kafka的配置问题,例如max.message.bytes,但没有一个是真的。 然后我想也许是因为加入,但没有发现任何会改变生产者运作方式的方式。

不确定是否相关,但是我们所有的Kafka应用程序都在使用Avro和Schema Registry ...

无论生产方法如何,偏移量应始终增加1,还是使用Kafka流API不能提供与普通Producer Consumer客户相同的保证?

是我完全想念的东西吗?

2 个答案:

答案 0 :(得分:3)

即使JavaDocs指明了此消息偏移量(似乎应该更新JavaDocs),也不是将消息偏移量增加1的正式API合同。

  • 如果不使用事务,则将获得至少一次语义或没有保证(有人称此为一次语义)。对于至少一次,记录可能被写入两次,因此,由于重复写入会“消耗”两个偏移量,因此两个连续消息的偏移量并不会真正增加一个。

  • 如果使用事务,则事务的每个提交(或中止)都会在该主题中写入一个提交(或中止)标记-这些事务标记还“消耗”一个偏移量(这是您观察到的)。

因此,通常您不应依赖连续的偏移量。您唯一得到的保证是,每个偏移量在分区内都是唯一的。

答案 1 :(得分:0)

我知道了解消息的偏移量可能很有用。但是,Kafka仅保证消息X的偏移量大于最后一条消息(X-1)的偏移量。顺便说一句,理想的解决方案不应基于偏移量计算。

在幕后,kafka生产者可能会尝试重新发送消息。同样,如果经纪人破产,那么可能会发生再平衡。一次语义可能会附加一条消息。因此,如果发生上述任何事件,则您的邮件的偏移量可能会发生变化。

Kafka可能会出于内部目的向该主题添加其他消息。但是Kafka的使用者API可能会丢弃这些内部消息。因此,您只能看到您的消息,并且消息的偏移量不一定会增加1。