[KAFKA] KAFKA消费者自动提交机制
什么是Offset?
-
假设我们正在从一个 Topic 中消费消息,这个时候我们的这个消费者(客户端)宕机了。我们意识到这不是世界的末日,我们可以从宕机中恢复,重新开始消费。我们可以从我们上一次离开的地方重新接收消息,这非常灵巧。
-
发生这样的事情是因为两个原因:
- 一个是一个叫 “Offset” 的东西
- 另外一个是一些 Consumer 的默认的值。
- Offset 是一块元数据,一个整数,会针对每一个 partition 上接收到的消息而持续增长。
- 每一个消息在一个
partition上将会有唯一的一个Offset。
offset会被存在一个叫做_consumer_offsets的topic中。
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 确认的位置开始消费。
X 参考文献
本文作者:
千千寰宇
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!

浙公网安备 33010602011771号