卡夫卡消费者组织没有丢失提交的消息

时间:2018-03-19 10:10:24

标签: go apache-kafka

我正在使用只有一个消费者的消费者群体,只有一个经纪人(docker wurstmeister图像)。在代码中决定是否提交偏移量 - 如果代码返回错误,则不提交消息。我需要确保系统不会丢失任何消息 - 即使这意味着永远重试相同的消息(现在;))。为了测试这个,我创建了一个简单的处理程序,它不会在'error'字符串发送为kafka的消息时提交偏移量。所有其他字符串都被提交。

kafka-console-producer --broker-list localhost:9092 --topic test
>this will be commited

正在运行

kafka-run-class kafka.admin.ConsumerGroupCommand --bootstrap-server localhost:9092 --group michalgrupa --describe

返回

TOPIC                          PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG        CONSUMER-ID                                       HOST                           CLIENT-ID
test                           0          13              13              0

所以没关系,没有滞后。现在我们传递'error'字符串来假装发生了一些不好的事情并且没有提交消息:

TOPIC                          PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG        CONSUMER-ID                                       HOST                           CLIENT-ID
test                           0          13              14              1

当前偏移量保持在正确位置+有1个滞后消息。现在,如果我们再次传递正确的消息,则偏移将继续到15:

TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG test 0 15 15

并且不会再次拾取第14号消息。这是默认行为吗?我是否需要手动跟踪上次偏移并加载消息+ 1?我已将提交间隔设置为0,希望不使用任何auto.commit机制。

获取/提交代码:

go func() {
    for {
        ctx := context.Background()

        m, err := mr.brokerReader.FetchMessage(ctx)
        if err != nil {
            break
        }

        if err := msgFunc(m); err != nil {
            log.Errorf("# messaging # cannot commit a message: %v", err)
            continue
        }

        // commit message if no error
        if err := mr.brokerReader.CommitMessages(ctx, m); err != nil {
            // should we do something else to just logging not committed message?
            log.Errorf("cannot commit message [%s] %v/%v: %s = %s; with error: %v", m.Topic, m.Partition, m.Offset, string(m.Key), string(m.Value), err)
        }
    }
}()

读者配置:

kafkaReader := kafka.NewReader(kafka.ReaderConfig{
Brokers:         brokers,
GroupID:         groupID,
Topic:           topic,
CommitInterval:  0,
MinBytes:        10e3,
MaxBytes:        10e6,
})

使用的库:https://github.com/segmentio/kafka-go

3 个答案:

答案 0 :(得分:1)

在kafka中,您只需提交偏移量而不是单个消息。如果我理解你的代码是正确的(不是go-developer)。您只需在收到无效邮件后继续操作。如果在无效消息之后出现有效消息,您将再次提交偏移量 - 我猜这不是您的意图。

只是要明确提交或提交偏移量的含义:您的消费者群体将偏移量存储到专用的内部kafka主题(或者在zookeeper上的旧版kafka版本上)。偏移可以标识主题中的单个位置(或者更精确地标识给定主题的分区)。这意味着您只能以线性方式使用主题。

在这里你可以看到kafka-consumer方面会发生什么:

New Kafka Consumer

您正在使用(很可能是多个)堆栈消息。您在此主题/分区提交位置(a.k.a偏移量)。所以你可以说我想再次重新创建一个特定的消息。您可以做的是在点击无效消息后停止消费。在这种情况下,您的问题将是:我如何摆脱此消息。从kafka主题中删除单个消息很棘手。一种常见的模式是将此消息写入某种死信主题,并与不同的消费者一起处理。

希望你能让事情变得更加清晰。

答案 1 :(得分:0)

您的Kafka使用者似乎已设置为自动提交偏移量(这是默认设置)。
如果是这样,这可能就是您的应用跳过错误消息的原因-尽管您跳过了CommitMessages调用,但提交是在后台线程上执行的
请在文档中查看enable.auto.commit的属性规范:https://kafka.apache.org/documentation/#newconsumerconfigs

答案 2 :(得分:0)

在这里有必要了解消费者补偿的概念。对于正在运行的使用者应用程序,它将消费消息的偏移量存储在内存中,而与提交/取消提交偏移量无关,如果重新启动使用者应用程序,它将检索“ CURRENT-OFFSET”的偏移量以继续使用。