1、Kafka的消费者提交方式
1)、自动提交,这种方式让消费者来管理位移,应用本身不需要显式操作。当我们将enable.auto.commit设置为true,那么消费者会在poll方法调用后每隔五秒(由auto.commit.interval.ms指定)提交一次位移。和很多其他操作一样,自动提交也是由poll方法来驱动的,在调用poll方法的时候,消费者判断是否到达提交时间,如果是则提交上一次poll返回的最大位移。需要注意的是,这种方式可能会导致消息重复消费,假如,某个消费者poll消息后,应用正在处理消息,在3秒后kafka进行了重平衡,那么由于没有更新位移导致重平衡后这部分消息重复消费。
2)、同步提交。
1 package com.demo.kafka.consumer;2
3 import java.time.Duration;4 import java.util.Arrays;5 import java.util.Collections;6 import java.util.List;7 import java.util.Properties;8 import java.util.regex.Pattern;9
10 import org.apache.kafka.clients.consumer.ConsumerConfig;11 import org.apache.kafka.clients.consumer.ConsumerRecord;12 import org.apache.kafka.clients.consumer.ConsumerRecords;13 import org.apache.kafka.clients.consumer.KafkaConsumer;14 import org.apache.kafka.clients.consumer.OffsetAndMetadata;15 import org.apache.kafka.clients.producer.ProducerConfig;16 import org.apache.kafka.common.TopicPartition;17 import org.apache.kafka.common.serialization.StringDeserializer;18
19 public classKafkaConsumerSimple {20
21 //设置服务器地址
22 private static final String bootstrapServer = "192.168.110.142:9092";23
24 //设置主题
25 private static final String topic = "topic-demo";26
27 //设置主题
28 private static final String topic2 = "topic-demo2";29
30 //设置消费者组
31 private static final String groupId = "group.demo";32
33 public static voidmain(String[] args) {34 Properties properties = newProperties();35 //设置反序列化key参数信息
36 properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());37 //设置反序列化value参数信息
38 properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());39
40 //设置服务器列表信息,必填参数,该参数和生产者相同,,制定链接kafka集群所需的broker地址清单,可以设置一个或者多个
41 properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServer);42
43 //设置消费者组信息,消费者隶属的消费组,默认为空,如果设置为空,则会抛出异常,这个参数要设置成具有一定业务含义的名称
44 properties.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);45
46 //制定kafka消费者对应的客户端id,默认为空,如果不设置kafka消费者会自动生成一个非空字符串。
47 properties.put("client.id", "consumer.client.id.demo");48
49 //设置每次从最早的offset开始消费
50 properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");51
52 //手动提交开启
53 properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);54
55 //将参数设置到消费者参数中
56 KafkaConsumer consumer = new KafkaConsumer(properties);57
58 //消息订阅59 //consumer.subscribe(Collections.singletonList(topic));60 //可以订阅多个主题61 //consumer.subscribe(Arrays.asList(topic, topic2));62 //可以使用正则表达式进行订阅63 //consumer.subscribe(Pattern.compile("topic-demo*"));64
65 //指定订阅的分区
66 TopicPartition topicPartition = new TopicPartition(topic, 0);67 consumer.assign(Arrays.asList(topicPartition));68
69 //初始化offset位移为-1
70 long lastConsumeOffset = -1;71 while (true) {72 //每隔一秒监听一次,拉去指定主题分区的消息
73 ConsumerRecords records = consumer.poll(Duration.ofMillis(1000));74 if(records.isEmpty()) {75 break;76 }77 //获取到消息
78 List> partitionRecords =records.records(topicPartition);79 //获取到消息的offset位移信息,最后消费的位移
80 lastConsumeOffset = partitionRecords.get(partitionRecords.size() - 1).offset();81 //System.out.println("the last offset is " + lastConsumeOffset);82 //同步提交消费位移
83 consumer.commitSync();84 }85 //当前消费者最后一个消费的位置
86 System.out.println("consumed offset is" +lastConsumeOffset);87 //提交,下次消费从哪个位置开始
88 OffsetAndMetadata committed =consumer.committed(topicPartition);89 System.out.println("committed offset is" +committed.offset());90 //下次消费从哪个位置开始
91 long position =consumer.position(topicPartition);92 System.out.println("the offset of the next record is" +position);93
94 }95
96 }
3)、异步提交方式。手动提交有一个缺点,就是当发起提交时调用应用会阻塞。当然我们可以减少手动提交的频率,但这个会增加消息重复的概率(和自动提交一样)。另外一个解决方法是,使用异步提交。但是异步提交也有一个缺点,那就是如果服务器返回提交失败,异步提交不会进行重试。相比较起来,同步提交会进行重试知道成功或者最后抛出异常给应用。异步提交没有实现重试是因为,如果同时存在多个异步提交,进行重试可能会导致位移覆盖。比如,我们发起一个异步提交commitA,此时提交位