1.提交的内容:
消费者无论时自动提交还是手动提交,都需要把所属的消费组+消费的某个主题+消费的某个分区及消费的偏移量,这样的信息提交到集群的_consumer_offset主题里面
2.自动提交offset(偏移量):
消息poll下来之后直接提交offset到_consumer_offset主题中
自动提交会丢失消息:因为如果poll下来之后 还没有消费 然后马上提交了offset 提交上去以后消费者挂了
3.手动提交offset:
- 手动同步提交:消费完消息后,调用同步提交方法,当集群返回ack前一直阻塞,返回ack后表示提交成功,然后执行之后的逻辑
- 手动异步提交:在消息消费完后,不需要等到集群ack,直接执行之后的逻辑,可以设置一个回调的方法
//有消息
if(records.count() > 0){
//手动提交offset,当前线程会阻塞直到offset提交成功
//一般使用同步提交,因为提交之后一般也没有什么逻辑代码了
//手动同步提交
consumer.commitSync();
//手动异步提交offset,当前线程提交offset不会阻塞,可以继续处理后面的程序逻辑
consumer.commitAsync(new OffsetCommitCallback() {
@Override
public void onComplete(Map<TopicPartition, OffsetAndMetadata> map, Exception e) {
if(e != null){
System.err.println("Commit falide for"+ map);
System.err.println("Commit falide exception"+ e.getStackTrace());
}
}
});
}
消费者代码根据offset加入提交逻辑
package Consumer;
import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.serialization.StringSerializer;
import java.time.Duration;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
/**
* 消费者
*/
public class MyConsumer {
private final static String TOPIC_NAME = "my-one-topic";
//消费组
private final static String CONSUMER_GROUP_NAME = "group-lzl";
public static void main(String[] args) {
Properties props = new Properties();
//设置broker集群ip
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"123.60.111.191:9091");
//是否自动offset,默认为true
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,"false");
//自动offset的间隔时间
props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG,1000);
//消费分组名
props.put(ConsumerConfig.GROUP_ID_CONFIG,CONSUMER_GROUP_NAME);
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
//创建一个消费者的客户端
KafkaConsumer<String,String> consumer = new KafkaConsumer<String, String>(props);
//消费者订阅主题列表
consumer.subscribe(Arrays.asList(TOPIC_NAME));
while (true){
ConsumerRecords<String,String> records = consumer.poll(Duration.ofMillis(1000));
for (ConsumerRecord<String, String> record : records) {
System.out.printf("收到消息:partition = %d,offset = %d,key = %s ,value = %s%n",
record.partition(),record.offset(),record.key(),record.value());
}
//有消息
if(records.count() > 0){
//手动提交offset,当前线程会阻塞直到offset提交成功
//一般使用同步提交,因为提交之后一般也没有什么逻辑代码了
//手动同步提交
consumer.commitSync();
//手动异步提交offset,当前线程提交offset不会阻塞,可以继续处理后面的程序逻辑
consumer.commitAsync(new OffsetCommitCallback() {
@Override
public void onComplete(Map<TopicPartition, OffsetAndMetadata> map, Exception e) {
if(e != null){
System.err.println("Commit falide for"+ map);
System.err.println("Commit falide exception"+ e.getStackTrace());
}
}
});
}
}
}
}