1.偏移量
- kafka的消息所在的位置由Topic、Partitions、Offsets三个因素决定。
- Offset代表Partition中的消息的顺序ID。
- 例如:第一个进入的Offset为0,第二个为1,以此类推。由于消费者消费Kafka消息也与Offset和consumer的group.id有关,故此维护好消息的Offset对于避免消息的重复消费与遗漏消费,确保消息的Exactly-once是至关重要的。
2. 提交偏移量
- 当我们在程序中使用poll()拉取消息时,Kafka总是返回生产者写入但还没有被消费者消费过的消息。
- Kafka不会像RabbitMQ那样需要得到消费者的确认,而是使用提交偏移量的方式表示消费者已经消费过该消息。
2.1 如何提交偏移量?
- 消费者消费消息后会往 __consumer_offsets 的主题中发送 消息,消息里包含每个分区的偏移量。
- Kafka就是使用消息在分区中的偏移量(位置)来追踪消息的,也就是说我们同样可以通过这种方式追踪到哪些记录是被群组里的哪个消费者消费的。
2.2 Group偏移量__consumer_offsets保存分区计算
-
根据group.id,Kafka会使用下面公式计算该group位移保存在__consumer_offsets的哪个分区上(默认50个分区)
-
kafka.coordinator.group.GroupMetadataManager.scala
-
public int partitionFor(final String groupId) { // 相当于取模 return Utils.abs(groupId.hashCode()) % this.groupMetadataTopicPartitionCount(); }
-
2.3 consumerGroup相关命令
# kafka-consumer-groups使用示例
# -----------------------------------------
$ kafka-consumer-groups.sh --bootstrap-server localhost:9092,localhost:9093,localhost:9094 --list
# 查看消费者组
$ kafka-consumer-groups.sh --bootstrap-server 192.168.56.105:9092 --list
# 查看某个消费者组
$ kafka-consumer-groups.sh --bootstrap-server 192.168.56.105:9092 --describe --group ConsumerGroup1
# 查看消费者组的成员详情
$ kafka-consumer-groups.sh --bootstrap-server 192.168.56.105:9092 --describe --group ConsumerGroup1 --members --verbose
# 查看消费者组的偏移量详情
$ kafka-consumer-groups.sh --bootstrap-server 192.168.56.105:9092 --describe --group ConsumerGroup1 --offsets --verbose
# 查看消费者组的状态详情
$ kafka-consumer-groups.sh --bootstrap-server 192.168.56.105:9092 --describe --group ConsumerGroup1 --state --verbose
# 查看指定consumer group的位移信息
# -----------------------------------------
# 查看偏移量主题(非格式化)
$ kafka-console-consumer.sh --bootstrap-server 192.168.56.105:9092 --topic __consumer_offsets --partition 39 --from-beginning
# 查看偏移量主题(格式化后)
$ kafka-run-class.sh kafka.tools.ConsoleConsumer --topic __consumer_offsets --bootstrap-server 192.168.56.105:9092 --formatter "kafka.coordinator.group.GroupMetadataManager\$OffsetsMessageFormatter" --from-beginning --partition 40
# 查看组信息
$ kafka-run-class.sh kafka.tools.ConsoleConsumer --topic __consumer_offsets --bootstrap-server 192.168.56.105:9092 --formatter "kafka.coordinator.group.GroupMetadataManager\$GroupMetadataMessageFormatter" --from-beginning --partition 40
3. 偏移量提交方式
-
自动提交
-
提交当前偏移量
-
异步提交
-
同步异步提交(常用、推荐)
-
提交特定偏移量(常用、推荐)
3.1 自动提交
参数配置:
// 开启自动提交 props.setProperty("enable.auto.commit", "true"); // 提交偏移量的时间间隔 props.setProperty("auto.commit.interval.ms", "1000");
自动提交是在轮询中进行,消费者每次轮询时都会检查是否提交该偏移量。这种情况就会发生重复消费和丢失消息的情况。
3.2 提交当前偏移量
参数配置:
// 关闭自动提交 props.put("enable.auto.commit", false); // 业务处理结束执行 try { // 这里进行提交 // 用commitSync()提交由poll方法返回的最新偏移量,如果提交成功马上返回,提交失败则抛出异常。 consumer.commitSync(); } catch (CommitFailedException e) { System.out.println(e.getMessage()); }
缺点:
-
在于提交请求后,broker响应之前应用程序会一直阻塞,这样就会限制应用程序的吞吐量。
-
一旦发生再均衡,会增加重复消息的数量
3.3 异步提交
// 关闭自动提交 props.put("enable.auto.commit", false); // 业务处理 // 异步提交 consumer.commitAsync();
3.4 同步异步提交
如果提交失败发生在关闭消费者或者再均衡前的最后一次提交,那么就要确保提交能够成功。这个时候可以使用同步异步组合提交
/* 关闭自动确认选项 */ props.put("enable.auto.commit", false); // 在必须要时提交偏移量,而不是基于时间 //props.put("auto.commit.interval.ms", "1000"); KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props); consumer.subscribe(Arrays.asList(TOPIC_NAME)); try { for (; ; ) { ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100)); for (ConsumerRecord<String, String> record : records) { System.out.printf("topic=%s, partition=%d, offset=%d, key=%s, value=%s\n", record.topic(), record.partition(), record.offset(), record.key(), record.value()); } // 异步提交速度更快 consumer.commitAsync(); } } finally { // 关闭前或者再均衡前的最后一次提交,要确保能够提交成功 consumer.commitSync(); // 提交,并告知coordinate将要离开消费者组 consumer.close(); }
3.5 提交特定偏移量
如果想要在批次中间提交偏移量,消费者API允许在调用commitSync和commitAsync时传递希望提交的分区和偏移量
-