Kafka 之 enable.auto.commit 的理解与使用

什么是Offset

假设我们正在从一个 Topic 中消费消息,这个时候我们的这个消费者(客户端)宕机了。我们意识到这不是世界的末日,我们可以从宕机中恢复,重新开始消费。我们可以从我们上一次离开的地方重新接收消息,这非常灵巧。

发生这样的事情是因为两个原因。一个是一个叫 “Offset” 的东西,另外一个是一些 Consumer 的默认的值。

Offset 是一块元数据,一个整数,会针对每一个 partition 上接收到的消息而持续增长。每一个消息在一个 partition 上将会有唯一的一个Offset。

offset会被存在一个叫做_consumer_offsets的主题中。


enable.auto.commit

通过字面意思我们不难理解这是kafka的自动提交功能。
配置消费者(配置enable.auto.commit为 true 配置自动提交)
enable.auto.commit 的默认值是 true;就是默认采用自动提交的机制。

auto.commit.interval.ms 的默认值是 5000,单位是毫秒。

此时我们配置消息消费后自动提交offset 位置

@Bean
public KafkaConsumer<String, String> kafkaConsumer() {
    Map<String, Object> config = new HashMap<>();
    config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "127.0.0.1:9092");
    config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
    config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
    config.put(ConsumerConfig.GROUP_ID_CONFIG, "groupId");
    config.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);
    KafkaConsumer<String, String> consumer = new KafkaConsumer<>(config);
    return consumer;
}

配置消息监听

@Slf4j
@Component
public class PackageMessageConsumer {

    @Autowired
    KafkaConsumer<String, String> kafkaConsumer;
    @Autowired
    EventProcessMaster eventProcessMaster;

    @PostConstruct
    public void listenRealTimeGroup() {
        new Thread(() -> consumer()).start();
    }

 private void consumer() {
 List<String> topics = new ArrayList<>();
        topics.add("test-kafka-auto.commit");
        kafkaConsumer.subscribe(topics);
        while(true) {
            try {
                // 拉取消息时间间隔 ms
                ConsumerRecords<String, String> records = kafkaConsumer.poll(10);
                for (ConsumerRecord<String, String> record : records) {
                    String key = record.key();
                    Object content =  record.value();
                    eventProcessMaster.processRequest(new Event(record.topic(), key, content));
                }
            } catch (Exception e){
                log.error(e.getMessage());
            }
        }
    }
}

配置自动提交offset 位置之后,我们不必关心消息消费到了什么位置,当程序重启后,消息也不会重复消费;

配置消费者(配置ENABLE_AUTO_COMMIT_CONFIG为 false 配置手动提交)
手动提交顾名思义就是每次我们消费后,kafka不会手动更新offset 位置,同时auto.commit.interval.ms 也就不被再考虑了。

@Bean
public KafkaConsumer<String, String> kafkaConsumer() {
    Map<String, Object> config = new HashMap<>();
    config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "127.0.0.1:9092");
    config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
    config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
    config.put(ConsumerConfig.GROUP_ID_CONFIG, "groupId");
    // 与自动提交的区别
    config.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
    KafkaConsumer<String, String> consumer = new KafkaConsumer<>(config);
    return consumer;
}

当我们设置成手动提交后,不修改其他代码会发现每次重启程序,kafka都会将我们没清理的所有数据都重新消费一遍,与我们需求的幂等性不符,将代码进行完善

@Bean
    public KafkaConsumer<String, String> kafkaConsumer() {
        Map<String, Object> config = new HashMap<>();
        config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "127.0.0.1:9092");
        config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
        config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
        config.put(ConsumerConfig.GROUP_ID_CONFIG, "groupId");
        // 与自动提交的区别
        config.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "100");// 自动提交时间间隔
        config.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(config);
        return consumer;
    }
@Slf4j
@Component
public class DependPackageMessageConsumer {

 @Autowired
    KafkaConsumer<String, String> kafkaConsumer;
    @Autowired
    EventProcessMaster eventProcessMaster;

    @PostConstruct
    public void listenRealTimeGroup() {
        new Thread(() -> consumer()).start();
    }

 private void consumer() {
 List<String> topics = new ArrayList<>();
        topics.add("test-kafka-auto.commit");
        kafkaConsumer.subscribe(topics);
        while(true) {
            try {
                ConsumerRecords<String, String> records = kafkaConsumer.poll(10);
                for (ConsumerRecord<String, String> record : records) {
                    String key = record.key();
                    Object content =  record.value();
                    eventProcessMaster.processRequest(new Event(record.topic(), key, content));
                }
                // 手动提交 offset 位置
                kafkaConsumer.commitSync();
            } catch (Exception e){
                log.error(e.getMessage());
            }
        }
    }
}

加上手动确认后服务重启,每次都会从上次offset 确认的位置开始消费。


参考文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值