【问题标题】:kafka stop consuming message from new assigned partitions after rebalancingkafka 在重新平衡后停止使用来自新分配的分区的消息
【发布时间】:2017-09-10 07:52:34
【问题描述】:

我对 kafka 很陌生(对英语也很陌生...),我面临这个问题,无法谷歌任何解决方案。

我使用spring-boot,spring-kafka支持,我在本地机器上安装了kafka_2.11-0.10.1.1(只有一个broker 0)

s1.then 我通过

创建主题
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 5 --topic tracking

我的消费者配置: 应用程序.properties:

kafka.servers.bootstrap=localhost:9092 
kafka.topic.tracking=tracking
kafka.group.id=trackingGroup
kafka.client.id=client-1

s2。然后我通过更改“kafka.client.id”启动 3 个消费者并运行 spring-boot main class 。在 Eclipse 控制台上,我可以检查分区分配:

client-1: partitions assigned:[tracking-4, tracking-3]
client-2: partitions assigned:[tracking-2, tracking-1]
client-3: partitions assigned:[tracking-0]

s3。启动 pruducer 向主题发送 20 条消息,每条消息开始消费特定分区的消息

s4。我关闭了消费 1,kafka 自动重新平衡, 新分区分配:

client-1: partitions assigned:[]
client-2: partitions assigned:[tracking-2,tracking-1, tracking-0]
client-3: partitions assigned:[tracking-4,tracking-3]

s5。我发现分区“tracking-3”上的消息没有被消耗!!

问题每次都可以重现,新分配的分区中的一些消息丢失,你有什么建议吗?请帮帮我,谢谢

【问题讨论】:

  • 我不确定您在什么时候关闭了 client-1。客户端 1 可能在关闭之前已经消耗了来自 tracking-3 的所有消息。关闭 client-1 后,您是否尝试向主题发送更多消息?
  • 我按 ctrl+c 关闭 client-1,client-1 没有在 tracking-3 中消耗所有消息,我已经尝试了很多次更多的消息。但仍然丢失消息

标签: spring apache-kafka spring-kafka


【解决方案1】:

我复制了它;重新平衡时,kafka 本身(auto.comit.enabled=true)似乎存在问题,kafka 将未读分区(the offset of the <i>next record</i> that will be fetched (if a record with that offset exists))的“位置”报告为分区结束。

其实我在使用kafka-consumer-groups工具的时候,未读分区的偏移量已经在“端”了。当我只使用一个消费者运行它时,它正在读取第一个分区,我看到...

$ kafka-consumer-groups --bootstrap-server localhost:9092 --describe -group so43405009

TOPIC                          PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG        CONSUMER-ID                                       HOST                           CLIENT-ID
tracking                       0          37              40              3          client1-8129bb3d-3a83-4c83-9128-3a2762ede758      /10.0.0.6                      client1
tracking                       1          40              40              0          client1-8129bb3d-3a83-4c83-9128-3a2762ede758      /10.0.0.6                      client1
tracking                       2          40              40              0          client1-8129bb3d-3a83-4c83-9128-3a2762ede758      /10.0.0.6                      client1
tracking                       3          40              40              0          client1-8129bb3d-3a83-4c83-9128-3a2762ede758      /10.0.0.6                      client1
tracking                       4          40              40              0          client1-8129bb3d-3a83-4c83-9128-3a2762ede758      /10.0.0.6                      client1

注意 CURRENT_OFFSET 列。

在下一次运行时,我运行了两次,一次是在处理第一个分区时,然后再一次......

TOPIC                          PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG        CONSUMER-ID                                       HOST                           CLIENT-ID
tracking                       0          41              44              3          client1-56d78a4b-f2df-4e31-8c5d-f8a1d8f64cf8      /10.0.0.6                      client1
tracking                       1          44              44              0          client1-56d78a4b-f2df-4e31-8c5d-f8a1d8f64cf8      /10.0.0.6                      client1
tracking                       2          44              44              0          client1-56d78a4b-f2df-4e31-8c5d-f8a1d8f64cf8      /10.0.0.6                      client1
tracking                       3          44              44              0          client1-56d78a4b-f2df-4e31-8c5d-f8a1d8f64cf8      /10.0.0.6                      client1
tracking                       4          44              44              0          client1-56d78a4b-f2df-4e31-8c5d-f8a1d8f64cf8      /10.0.0.6                      client1

TOPIC                          PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG        CONSUMER-ID                                       HOST                           CLIENT-ID
tracking                       0          44              44              0          client1-56d78a4b-f2df-4e31-8c5d-f8a1d8f64cf8      /10.0.0.6                      client1
tracking                       1          44              44              0          client1-56d78a4b-f2df-4e31-8c5d-f8a1d8f64cf8      /10.0.0.6                      client1
tracking                       2          41              44              3          client1-56d78a4b-f2df-4e31-8c5d-f8a1d8f64cf8      /10.0.0.6                      client1
tracking                       3          44              44              0          client1-56d78a4b-f2df-4e31-8c5d-f8a1d8f64cf8      /10.0.0.6                      client1
tracking                       4          44              44              0          client1-56d78a4b-f2df-4e31-8c5d-f8a1d8f64cf8      /10.0.0.6                      client1

查看分区 2 的当前偏移量如何从 44 下降到 41。

禁用自动提交为我解决了这个问题...

spring.kafka.consumer.enable-auto-commit=false

...

TOPIC                          PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG        CONSUMER-ID                                       HOST                           CLIENT-ID
tracking                       0          52              52              0          client1-59413599-81e8-49dd-bbd7-8a62152f11e5      /10.0.0.6                      client1
tracking                       1          49              52              3          client1-59413599-81e8-49dd-bbd7-8a62152f11e5      /10.0.0.6                      client1
tracking                       2          49              52              3          client2-edfe34f9-08d5-4825-80d0-4a6cf9526e42      /10.0.0.6                      client2
tracking                       3          48              52              4          client2-edfe34f9-08d5-4825-80d0-4a6cf9526e42      /10.0.0.6                      client2
tracking                       4          51              52              1          client3-20da8742-af38-403e-b125-5d0c7c771319      /10.0.0.6                      client3

这是我的测试程序:

@SpringBootApplication
public class So43405009Application implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(So43405009Application.class, args);
    }

    @Autowired
    private KafkaTemplate<String, String> template;

    @Value("${spring.kafka.consumer.client-id}")
    private String clientId;

    @Override
    public void run(String... args) throws Exception {
        if (this.clientId.endsWith("1")) {
            for (int i = 0; i < 20; i++) {
                this.template.sendDefault("foo" + i);
            }
        }
    }

    @Bean
    public KafkaMessageListenerContainer<String, String> container(ConsumerFactory<String, String> cf) {
        ContainerProperties containerProperties = new ContainerProperties("tracking");
        containerProperties.setMessageListener((MessageListener<?, ?>) d -> {
            System.out.println(d);
            try {
                Thread.sleep(5_000);
            }
            catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        KafkaMessageListenerContainer<String, String> container = new KafkaMessageListenerContainer<>(cf,
                containerProperties);
        return container;
    }

}

有属性

spring.kafka.listener.ack-mode=record
spring.kafka.consumer.enable-auto-commit=false
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.group-id=so43405009
spring.kafka.consumer.client-id=client1
spring.kafka.template.default-topic=tracking

我在 0.10.2.0 中也看到了相同的结果。

编辑

原来是spring-kafka bug;它可以在启用自动提交的情况下使用,但您必须明确启用它

spring.kafka.consumer.enable-auto-commit=true

否则容器会假定它是false 并导致上述奇怪的行为 - 如果启用了自动提交,看起来客户端不喜欢调用消费者的提交方法。 #288.

我通常建议设置为 false,然后选择容器的 AckModes 之一;例如RECORD 在记录后提交,BATCH 在轮询收到的每个批次后提交(默认)。

【讨论】:

  • 有关根本原因和解决方法的更多详细信息,请参阅我的答案的编辑。
  • 我想听从你的建议 ---- "设置为 false,然后选择容器的 AckModes 之一;例如,RECORD 在每次记录后提交,在轮询收到的每个批次后进行 BATCH(默认)。”但是您能否提供一些代码示例或链接(使用 spring-kafka),因为我对 kafka 非常陌生,而且官方的 spring-kafka 文档似乎还不够。
  • 等一下,我发现这不能通过简单的添加 spring.kafka.consumer.enable-auto-commit=true 来解决,这会导致一些消息被消费两次!例如消息 m1 在分区 p1 并被消费者 c1 消费,此时我关闭 c1 并且 p1 被自动分配给消费 c2,我发现 c2 将再次消费 m1 .....
  • 这就是为什么我不建议使用自动提交 - 请参阅我的回答以设置 ackmode spring.kafka.listener.ack-mode=record spring.kafka.consumer.enable-auto-commit=false。或者,如果使用自动提交将auto.commit.interval.ms 减少到低于默认值 5000 的值。无论如何,您需要处理重复的可能性。见the apache kafka documentation。 kafka 尚不支持恰好一次交付。
猜你喜欢
  • 2021-01-26
  • 1970-01-01
  • 1970-01-01
  • 2017-12-17
  • 2019-06-20
  • 1970-01-01
  • 2016-01-21
  • 2013-04-17
  • 2019-04-16
相关资源
最近更新 更多