生产者每次调用poll()方法时,它总是返回由生产者写入Kafka但还没有消费的消息,如果消费者一致处于运行状态,那么分区消息偏移量就没什么用处,但是如果消费者发生崩溃或者有新的消费者加入群组,就会触发再均衡,完成再均衡之后,每个消费可能分配到新的分区,而不是之前处理的那个,为了能够继续之前的工作,消费者需要读取每个分区最后一次提交的偏移量,然后从偏移量制定的地方开始工作。消费者会往一个__consumer_offser的主题发送消息,消息里包含每个分区的偏移量。

1.同步提交

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer; import java.util.Collections;
import java.util.Properties; /**
* Created by zhangpeiran on 2018/10/9.
*/
public class MyConsumer { public static void main(String[] args){
Properties properties = new Properties();
properties.put("bootstrap.servers","ip:9092");
properties.put("key.deserializer","org.apache.kafka.common.serialization.StringDeserializer");
properties.put("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer");
properties.put("group.id","DemoConsumerGroup"); //默认值为latest,当消费者读取的分区没有偏移量或偏移量无效时,消费者将从最新的记录开始读
//当一个消费group第一次订阅主题时,符合这种情况,在Consumer启动之前,Producer生产的数据不会被读取
//置为earliest,表示从分区起始位置读取消息
properties.put("auto.offset.reset","earliest"); //设置手动提交消息偏移
properties.put("enable.auto.commit","false"); //一次拉取的最大消息条数
properties.put("max.poll.records",10); KafkaConsumer<String,String> consumer = new KafkaConsumer<String, String>(properties); consumer.subscribe(Collections.singletonList("Demo3")); int count = 0;
try {
while (true){
ConsumerRecords<String,String> records = consumer.poll(10);
for(ConsumerRecord<String ,String> record : records){
count ++;
if(count == 50)
consumer.commitSync();
System.out.println(record.topic() + "," + record.partition() + "," + record.offset() + "," + record.key() + "," + record.value());
}
System.out.println(count);
}
} finally {
consumer.close();
}
}
}

说明:在上述例子中,主题Demo3中已经有100条消息,第一次远行Consumer时,在读取到50条消息时,提交一次偏移量,输出的count值为100;第二次不改变消费group,会从51条开始读取,所以输出的count值为50

2. 异步提交,同步提交时,在broker回应指,会一直阻塞、重试,限制应用的吞吐量,因此可以采用异步提交,异步提交失败时不会重试,因为如果提交失败时因为临时的问题导致的,那么后续的提交总户有成功的。

consumer.commitAsync();

3. 同步、异步组合提交,确保消费者在关闭或者再均衡之前提交成功

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer; import java.util.Collections;
import java.util.Properties; /**
* Created by zhangpeiran on 2018/10/9.
*/
public class MyConsumer { public static void main(String[] args){
Properties properties = new Properties();
properties.put("bootstrap.servers","ip:9092");
properties.put("key.deserializer","org.apache.kafka.common.serialization.StringDeserializer");
properties.put("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer");
properties.put("group.id","DemoConsumerGroup"); //默认值为latest,当消费者读取的分区没有偏移量或偏移量无效时,消费者将从最新的记录开始读
//当一个消费group第一次订阅主题时,符合这种情况,在Consumer启动之前,Producer生产的数据不会被读取
//置为earliest,表示从分区起始位置读取消息
properties.put("auto.offset.reset","earliest"); //设置手动提交消息偏移
properties.put("enable.auto.commit","false"); //一次拉取的最大消息条数
properties.put("max.poll.records",10); KafkaConsumer<String,String> consumer = new KafkaConsumer<String, String>(properties); consumer.subscribe(Collections.singletonList("Demo3")); int count = 0;
try {
while (true){
ConsumerRecords<String,String> records = consumer.poll(10);
for(ConsumerRecord<String ,String> record : records){
count ++;
//if(count == 50)
//consumer.commitAsync();
//consumer.commitSync();
System.out.println(record.topic() + "," + record.partition() + "," + record.offset() + "," + record.key() + "," + record.value());
}
consumer.commitAsync();
//System.out.println(count);
}
} finally {
try {
consumer.commitSync();
} finally {
consumer.close();
}
//consumer.close();
}
}
}

5. 提交特定的偏移量。前面提交的是最后一个偏移量,poll可能返回了大批数据,这样在再均衡时,可能重复处理的消息比较多。消费者API提供了指定分区和偏移量来提交


import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.consumer.OffsetAndMetadata;
import org.apache.kafka.common.TopicPartition;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
* Created by zhangpeiran on 2018/10/9.
*/
public class MyConsumer {

public static void main(String[] args){
Properties properties = new Properties();
properties.put("bootstrap.servers","ip:9092");
properties.put("key.deserializer","org.apache.kafka.common.serialization.StringDeserializer");
properties.put("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer");
properties.put("group.id","DemoConsumerGroup");

//默认值为latest,当消费者读取的分区没有偏移量或偏移量无效时,消费者将从最新的记录开始读
//当一个消费group第一次订阅主题时,符合这种情况,在Consumer启动之前,Producer生产的数据不会被读取
//置为earliest,表示从分区起始位置读取消息
properties.put("auto.offset.reset","earliest");

//设置手动提交消息偏移
properties.put("enable.auto.commit","false");

//一次拉取的最大消息条数
properties.put("max.poll.records",1000);

KafkaConsumer<String,String> consumer = new KafkaConsumer<String, String>(properties);

consumer.subscribe(Collections.singletonList("Demo5"));

int cnt = 0;
int count = 0;
Map<TopicPartition,OffsetAndMetadata> currentOffsets = new HashMap<TopicPartition,OffsetAndMetadata>();
try {
while (true){
ConsumerRecords<String,String> records = consumer.poll(10);
for(ConsumerRecord<String ,String> record : records){
count ++;
//if(count == 50)
//consumer.commitAsync();
//consumer.commitSync();

//offset + 1,下次消费者从该偏移量开始拉取消息
currentOffsets.put(new TopicPartition(record.topic(),record.partition()),new OffsetAndMetadata(record.offset()+1,"no"));
if ((count / 10 == 1) && (count % 10 == 0)){
System.out.println(count);
consumer.commitSync(currentOffsets);
}
System.out.println(record.topic() + "," + record.partition() + "," + record.offset() + "," + record.key() + "," + record.value());
}
//consumer.commitAsync();

cnt ++;
}
} finally {
try {
//consumer.commitSync();
} finally {
consumer.close();
}
//consumer.close();
}
}
}
 

生产者生产了100条消息,上述代码的结果是:依次启动-暂停消费者10次,每次读取100,90,80,...10条消息,原因是每次消费者读取前10条的时候提交一次偏移量

Kafka消费者手动提交消息偏移的更多相关文章

  1. kafka 消费者拉取消息

    本文只跟踪消费者拉取消息的流程.对于 java 客户端, kafka 的生产者和消费者复用同一个网络 io 类 NetworkClient. 入口在 KafkaConsumer#pollOnce 中, ...

  2. Kafka学习笔记(7)----Kafka使用Cosumer接收消息

    1. 什么是KafkaConsumer? 应用程序使用KafkaConsul'le 「向Kafka 订阅主题,并从订阅的主题上接收消息.Kafka的消息读取不同于从其他消息系统读取数据,它涉及了一些独 ...

  3. 关于SpringKafka消费者的几个监听器:[一次处理单条消息和一次处理一批消息]以及[自动提交offset和手动提交offset]

    自己在使用Spring Kafka 的消费者消费消息的时候的实践总结: 接口 KafkaDataListener 是spring-kafka提供的一个供消费者接受消息的顶层接口,也是一个空接口; pu ...

  4. kafka多线程消费及处理和手动提交处理方案设计[转]

    转自:http://blog.csdn.net/haoyifen/article/details/54692503 kafka与其他消息队列不同的是, kafka的消费者状态由外部( 消费者本身或者类 ...

  5. kafka 0.10.2 消息消费者

    package cn.xiaojf.kafka.consumer; import org.apache.kafka.clients.consumer.ConsumerConfig; import or ...

  6. RocketMQ消息丢失解决方案:同步刷盘+手动提交

    前言 之前我们一起了解了使用RocketMQ事务消息解决生产者发送消息时消息丢失的问题,但使用了事务消息后消息就一定不会丢失了吗,肯定是不能保证的. 因为虽然我们解决了生产者发送消息时候的消息丢失问题 ...

  7. kafka消费者客户端(0.9.0.1API)

    转自:http://orchome.com/203 kafka客户端从kafka集群消费消息(记录).它会透明地处理kafka集群中服务器的故障.它获取集群内数据的分区,也和服务器进行交互,允许消费者 ...

  8. Kafka权威指南 读书笔记之(四)Kafka 消费者一一从 Kafka读取数据

    KafkaConsumer概念 消费者和消费者群组 Kafka 消费者从属于消费者群组.一个群组里的消费者订阅的是同一个主题,每个消费者接收主题一部分分区的消息. 往群组里增加消费者是横向伸缩消费能力 ...

  9. Kafka(分布式发布-订阅消息系统)工作流程说明

    Kafka系统架构Apache Kafka是分布式发布-订阅消息系统.它最初由LinkedIn公司开发,之后成为Apache项目的一部分.Kafka是一种快速.可扩展的.设计内在就是分布式的,分区的和 ...

随机推荐

  1. Hadoop大数据平台搭建之前期配置(2)

    环境:CentOS 7.4 (1708  DVD) 工具:VMware.MobaXterm 一. 克隆大数据集群 1. 选中已经进行了基本配置的虚拟机,进行克隆. 2. 此处改为"创建完整克 ...

  2. MathType中怎么编辑韩文字符

    用MathType编辑公式,所涉及到符号与字母一般都是英文字母与数字,或者使用希腊字母,当然还有很多使用中文的情况.但是不仅如此,我们在使用MathType时,除了这些字符之外,还可以输入韩文或者日文 ...

  3. 一个定时任务管理器,基于Go语言和beego框架开发

    链接 https://github.com/lisijie/webcron 安装说明 系统需要安装Go和MySQL. 获取源码 $ go get github.com/lisijie/webcron ...

  4. Java基础教程——多线程:创建线程

    多线程 进程 每一个应用程序在运行时,都会产生至少一个进程(process). 进程是操作系统进行"资源分配和调度"的独立单位. Windows系统的"任务管理器&quo ...

  5. Mybatis入门及第一个Mybatis程序

    Mybatis笔记整理 所需要的基础知识 JDBC Mysql Java基础 Maven Junit 框架:是有配置文件的.最好的方式:看官网文档 1.简介 1.1.什么是MyBatis 简介 什么是 ...

  6. kubelet CPU 使用率过高问题排查

    kubelet CPU 使用率过高问题排查 问题背景 客户的k8s集群环境,发现所有的worker节点的kubelet进程的CPU使用率长时间占用过高,通过pidstat可以看到CPU使用率高达100 ...

  7. mysql反序索引

    关于mysql的排序 参考:https://www.cnblogs.com/lccsblog/p/12733773.html 转载: https://www.cnblogs.com/lynn919/p ...

  8. spring与分布式事务

    转载:https://www.cnblogs.com/qianjun2017/p/8349829.html 转载:https://blog.csdn.net/jaryle/article/detail ...

  9. 【Python】我是如何使计算时间提速25.6倍的

    我是如何使计算时间提速25.6倍的 我的原始文档:https://www.yuque.com/lart/blog/aemqfz 在显著性目标检测任务中有个重要的评价指标, E-measure, 需要使 ...

  10. npm中的命令指令的参数的 简写介绍

    在使用npm时,使用的的缩写 install: 缩写为i,表示安装. --global: 缩写为-g,表示:全局标识,可以在任意目录中使用该工具.全局安装. --save: 缩写为-S,表示安装的包将 ...