java实现Kafka的消费者示例
使用java实现Kafka的消费者
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
package com.lisg.kafkatest;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Properties;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;import kafka.consumer.Consumer;import kafka.consumer.ConsumerConfig;import kafka.consumer.ConsumerIterator;import kafka.consumer.KafkaStream;import kafka.javaapi.consumer.ConsumerConnector;/** * java实现Kafka消费者的示例 * @author lisg * */public class KafkaConsumer { private static final String TOPIC = "test"; private static final int THREAD_AMOUNT = 1; public static void main(String[] args) { Properties props = new Properties(); props.put("zookeeper.connect", "vm1:2181"); props.put("group.id", "group1"); props.put("zookeeper.session.timeout.ms", "400"); props.put("zookeeper.sync.time.ms", "200"); props.put("auto.commit.interval.ms", "1000");; Map<String, Integer> topicCountMap = new HashMap<String, Integer>(); //每个topic使用多少个kafkastream读取, 多个consumer topicCountMap.put(TOPIC, THREAD_AMOUNT); //可以读取多个topic// topicCountMap.put(TOPIC2, 1); ConsumerConnector consumer = Consumer.createJavaConsumerConnector(new ConsumerConfig(props)); Map<String, List<KafkaStream<byte[], byte[]>>> msgStreams = consumer.createMessageStreams(topicCountMap ); List<KafkaStream<byte[], byte[]>> msgStreamList = msgStreams.get(TOPIC); //使用ExecutorService来调度线程 ExecutorService executor = Executors.newFixedThreadPool(THREAD_AMOUNT); for (int i = 0; i < msgStreamList.size(); i++) { KafkaStream<byte[], byte[]> kafkaStream = msgStreamList.get(i); executor.submit(new HanldMessageThread(kafkaStream, i)); } //关闭consumer try { Thread.sleep(20000); } catch (InterruptedException e) { e.printStackTrace(); } if (consumer != null) { consumer.shutdown(); } if (executor != null) { executor.shutdown(); } try { if (!executor.awaitTermination(5000, TimeUnit.MILLISECONDS)) { System.out.println("Timed out waiting for consumer threads to shut down, exiting uncleanly"); } } catch (InterruptedException e) { System.out.println("Interrupted during shutdown, exiting uncleanly"); } }}/** * 具体处理message的线程 * @author Administrator * */class HanldMessageThread implements Runnable { private KafkaStream<byte[], byte[]> kafkaStream = null; private int num = 0; public HanldMessageThread(KafkaStream<byte[], byte[]> kafkaStream, int num) { super(); this.kafkaStream = kafkaStream; this.num = num; } public void run() { ConsumerIterator<byte[], byte[]> iterator = kafkaStream.iterator(); while(iterator.hasNext()) { String message = new String(iterator.next().message()); System.out.println("Thread no: " + num + ", message: " + message); } } } |
|
1
|
props.put("auto.commit.interval.ms", "1000"); |
表示的是:consumer间隔多长时间在zookeeper上更新一次offset
说明:
为什么使用High Level Consumer?
有些场景下,从Kafka中读取消息的逻辑不处理消息的offset,仅仅是获取消息数据。High Level Consumer就提供了这种功能。
首先要知道的是,High Level Consumer在ZooKeeper上保存最新的offset(从指定的分区中读取)。这个offset基于consumer group名存储。
Consumer group名在Kafka集群上是全局性的,在启动新的consumer group的时候要小心集群上没有关闭的consumer。当一个consumer线程启动了,Kafka会将它加入到相同的topic下的相同consumer group里,并且触发重新分配。在重新分配时,Kafka将partition分配给consumer,有可能会移动一个partition给另一个consumer。如果老的、新的处理逻辑同时存在,有可能一些消息传递到了老的consumer上。
设计High Level Consumer
使用High LevelConsumer首先要知道的是,它应该是多线程的。消费者线程的数量跟tipic的partition数量有关,它们之间有一些特定的规则:
如果线程数量大于主题的分区数量,一些线程将得不到任何消息
如果分区数大于线程数,一些线程将得到多个分区的消息
如果一个线程处理多个分区的消息,它接收到消息的顺序是不能保证的。比如,先从分区10获取了5条消息,从分区11获取了6条消息,然后从分区10获取了5条,紧接着又从分区10获取了5条,虽然分区11还有消息。
添加更多了同consumer group的consumer将触发Kafka重新分配,某个分区本来分配给a线程的,从新分配后,有可能分配给了b线程。
关闭消费组和错误处理
Kafka不会再每次读取消息后马上更新zookeeper上的offset,而是等待一段时间。由于这种延迟,有可能消费者读取了一条消息,但没有更新offset。所以,当客户端关闭或崩溃后,从新启动时有些消息重复读取了。另外,broker宕机或其他原因导致更换了partition的leader,也会导致消息重复读取。
为了避免这种问题,你应该提供一个平滑的关闭方式,而不是使用kill -9
上面的java代码中提供一种关闭的方式:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
if (consumer != null) { consumer.shutdown();}if (executor != null) { executor.shutdown();}try { if (!executor.awaitTermination(5000, TimeUnit.MILLISECONDS)) { System.out.println("Timed out waiting for consumer threads to shut down, exiting uncleanly"); }} catch (InterruptedException e) { System.out.println("Interrupted during shutdown, exiting uncleanly");} |
在shutdown之后,等待了5秒钟,给consumer线程时间来处理完kafka stream里保留的消息。
参考资料:https://cwiki.apache.org/confluence/display/KAFKA/Consumer+Group+Example
附件列表
java实现Kafka的消费者示例的更多相关文章
- kafka集群搭建和使用Java写kafka生产者消费者
1 kafka集群搭建 1.zookeeper集群 搭建在110, 111,112 2.kafka使用3个节点110, 111,112 修改配置文件config/server.properties ...
- Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例
Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例 本文由 TonySpark 翻译自 Javarevisited.转载请参见文章末尾的要求. Java.util.concurr ...
- java实现Kafka生产者示例
使用java实现Kafka的生产者 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 3 ...
- Java版Kafka使用及配置解释
Java版Kafka使用及配置解释 一.Java示例 kafka是吞吐量巨大的一个消息系统,它是用scala写的,和普通的消息的生产消费还有所不同,写了个demo程序供大家参考.kafka的安装请参考 ...
- 初始 Kafka Consumer 消费者
温馨提示:整个 Kafka 专栏基于 kafka-2.2.1 版本. 1.KafkaConsumer 概述 根据 KafkaConsumer 类上的注释上来看 KafkaConsumer 具有如下特征 ...
- 第23章 java线程通信——生产者/消费者模型案例
第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...
- RocketMQ消费者示例程序
转载请注明出处:http://www.cnblogs.com/xiaodf/ 本博客实现了一个简单的RocketMQ消费者的示例,MQ里存储的是经过Avro序列化的消息数据,程序读取数据并反序列化后, ...
- JAVA版Kafka代码及配置解释
伟大的程序员版权所有,转载请注明:http://www.lenggirl.com/bigdata/java-kafka.html.html 一.JAVA代码 kafka是吞吐量巨大的一个消息系统,它是 ...
- Java操作Kafka
java操作kafka非常的简单,然后kafka也提供了很多缺省值,一般情况下我们不需要修改太多的参数就能使用.下面我贴出代码. pom.xml <dependency> <grou ...
随机推荐
- 剑指offer五十七之二叉树的下一个结点
一.题目 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针. 二.思路 结合图,我们可发现分成两大类: 1.有右子树 ...
- activity生命周期实例(不同启动模式)
1.生命周期的几个阶段介绍: onCreate: 表示activity被创建,做一些初始化工作如调用setContentView去加载界面布局资源.初始化Acitivity所需数据等. onResta ...
- 机器学习实战(一)k-近邻算法
转载请注明源出处:http://www.cnblogs.com/lighten/p/7593656.html 1.原理 本章介绍机器学习实战的第一个算法——k近邻算法(k Nearest Neighb ...
- springMVC执行流程及原理
spring的MVC执行原理 1.spring mvc将所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责对请求 进行真正的处理工作. 2.DispatcherSer ...
- Postman—脚本介绍
前言 Postman包含一个基于Node.js的强大的运行时环境,它允许我们为请求和集合添加动态行为.这使的我们可以编写测试用例,构建可包含动态参数的请求,在请求之间传递数据等等. 我们可以在流程中以 ...
- 数字和表达式(python)
>>>2+2 4 >>>1/2#(注:3.0版本之前是这样的,整数除法) >>>1.0/2.0 0.5 >>>1.0/2 0.5 ...
- CRF两个例子的理解
概率计算例子: 预测例子:
- WPF Style和Template
WPF中的Style类似于Web应用程序中的CSS,它是控件的一个属性,属于资源的一种. ControlTemplate和DataTemplate区别: ControlTemplate用于改变控件原来 ...
- docker 微镜像-alpine
刚想找maven自动发布项目到tomcat, 突然看到个好玩的, docker微镜像 -- alpine 直接粘一段: Alpine Linux Docker镜像基于Alpine Linux操作系统, ...
- prometheus安装、使用
本文主要参考https://songjiayang.gitbooks.io/prometheus/introduction/what.html 二进制包安装 我们可以到 Prometheus 二进制下 ...