设计Kafka的High Level Consumer
原文:https://cwiki.apache.org/confluence/display/KAFKA/Consumer+Group+Example
为什么使用High Level Consumer
在某些应用场景,我们希望通过多线程读取消息,而我们并不关心从Kafka消费消息的顺序,我们只关心数据能被消费即可。High Level 就是用于抽象这类消费动作的。
消息消费已Consumer Group为单位,每一个Consumer Group中能够有多个consumer。每一个consumer是一个线程,topic的每一个partition同一时候仅仅能被某一个consumer读 取,Consumer Group相应的每一个partition都有一个最新的offset的值,存储在zookeeper上的。所以不会出现反复消费的情况。
- 由于consumer的offerset并非实时的传送到zookeeper(通过配置来制定更新周期)。所以Consumer假设突然Crash,有可能会读取反复的信息
设计High Level Consumer
High Level Consumer 能够而且应该被使用在多线程的环境。线程模型中线程的数量(也代表group中consumer的数量)和topic的partition数量有关。以下列举一些规则:
- 当提供的线程数量多于partition的数量,则部分线程将不会接收到消息。
- 当提供的线程数量少于partition的数量,则部分线程将从多个partition接收消息。
- 当某个线程从多个partition接收消息时,不保证接收消息的顺序;可能出现从partition3接收5条消息。从partition4接收6条消息。接着又从partition3接收10条消息;
- 当加入很多其它线程时。会引起kafka做re-balance, 可能改变partition和线程的相应关系。
- 由于突然停止Consumer以及Broker会导致消息反复读的情况,为了避免这样的情况在shutdown之前通过Thread.sleep(10000)让Consumer有时间将offset同步到zookeeper
样例
Maven依赖
<!--Kafka 消息依赖-->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.10</artifactId>
<version>0.8.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>0.8.2.0</version>
</dependency>
Consumer 线程
import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;
import kafka.message.MessageAndMetadata; public class ConsumerThread implements Runnable {
private KafkaStream kafkaStream;
//线程编号
private int threadNumber;
public ConsumerThread(KafkaStream kafkaStream, int threadNumber) {
this.threadNumber = threadNumber;
this.kafkaStream = kafkaStream;
}
public void run() {
ConsumerIterator<byte[], byte[]> it = kafkaStream.iterator();
StringBuffer sb = new StringBuffer();
//该循环会持续从Kafka读取数据,直到手工的将进程进行中断
while (it.hasNext()) {
MessageAndMetadata metaData = it.next();
sb.append("Thread: " + threadNumber + " ");
sb.append("Part: " + metaData.partition() + " ");
sb.append("Key: " + metaData.key() + " ");
sb.append("Message: " + metaData.message() + " ");
sb.append("\n");
System.out.println(sb.toString());
}
System.out.println("Shutting down Thread: " + threadNumber);
}
}
其余程序
import kafka.consumer.ConsumerConfig;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector; 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; public class ConsumerGroupExample {
private final ConsumerConnector consumer;
private final String topic;
private ExecutorService executor; public ConsumerGroupExample(String a_zookeeper, String a_groupId, String a_topic) {
consumer = kafka.consumer.Consumer.createJavaConsumerConnector(
createConsumerConfig(a_zookeeper, a_groupId));
this.topic = a_topic;
} public void shutdown() {
if (consumer != null) consumer.shutdown();
if (executor != null) executor.shutdown();
} public void run(int a_numThreads) {
Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
topicCountMap.put(topic, new Integer(a_numThreads));
//返回的Map包括全部的Topic以及相应的KafkaStream
Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(topicCountMap);
List<KafkaStream<byte[], byte[]>> streams = consumerMap.get(topic); //创建Java线程池
executor = Executors.newFixedThreadPool(a_numThreads); // 创建 consume 线程消费messages
int threadNumber = 0;
for (final KafkaStream stream : streams) {
executor.submit(new ConsumerTest(stream, threadNumber));
threadNumber++;
}
} private static ConsumerConfig createConsumerConfig(String a_zookeeper, String a_groupId) {
Properties props = new Properties();
//指定连接的Zookeeper集群。通过该集群来存储连接到某个Partition的Consumer的Offerset
props.put("zookeeper.connect", a_zookeeper);
//consumer group 的ID
props.put("group.id", a_groupId);
//Kafka等待Zookeeper的响应时间(毫秒)
props.put("zookeeper.session.timeout.ms", "400");
//ZooKeeper 的‘follower’能够落后Master多少毫秒
props.put("zookeeper.sync.time.ms", "200");
//consumer更新offerset到Zookeeper的时间
props.put("auto.commit.interval.ms", "1000"); return new ConsumerConfig(props);
} public static void main(String[] args) {
String zooKeeper = args[0];
String groupId = args[1];
String topic = args[2];
int threads = Integer.parseInt(args[3]); ConsumerGroupExample example = new ConsumerGroupExample(zooKeeper, groupId, topic);
example.run(threads);
//由于consumer的offerset并非实时的传送到zookeeper(通过配置来制定更新周期),所以shutdown Consumer的线程,有可能会读取反复的信息
//添加sleep时间,让consumer把offset同步到zookeeper
try {
Thread.sleep(10000);
} catch (InterruptedException ie) { }
example.shutdown();
}
}
设计Kafka的High Level Consumer的更多相关文章
- Consumer设计-high/low Level Consumer
1 Producer和Consumer的数据推送拉取方式 Producer Producer通过主动Push的方式将消息发布到Broker n Consumer Consumer通过Pull从Br ...
- Kafka 学习笔记之 High Level Consumer相关参数
High Level Consumer相关参数 自动管理offset auto.commit.enable = true auto.commit.interval.ms = 60*1000 手动管理o ...
- .net Kafka.Client多个Consumer Group对Topic消费不能完全覆盖研究总结(一)
我们知道Kafka支持Consumer Group的功能,但是最近在应用Consumer Group时发现了一个Topic 的Partition不能100%覆盖的问题. 程序部署后,发现Kafka在p ...
- Kafka 学习笔记之 Consumer API
Kafka提供了两种Consumer API High Level Consumer API Low Level Consumer API(Kafka诡异的称之为Simple Consumer API ...
- .net Kafka.Client多个Consumer Group对Topic消费不能完全覆盖研究总结(二)
依据Partition和Consumer的Rebalance策略,找到Kafka.Client Rebalance代码块,还原本地环境,跟踪调试,发现自定义Consumer Group 的Consum ...
- Kafka客户端Producer与Consumer
Kafka客户端Producer与Consumer 一.pom.xml 二.相关配置文件 producer.properties log4j.properties base.properties 三. ...
- 漫游Kafka设计篇之Producer和Consumer
Kafka Producer 消息发送 producer直接将数据发送到broker的leader(主节点),不需要在多个节点进行分发.为了帮助producer做到这点,所有的Kafka节点都可以及时 ...
- 漫游Kafka设计篇之Producer和Consumer(4)
Kafka Producer 消息发送 producer直接将数据发送到broker的leader(主节点),不需要在多个节点进行分发.为了帮助producer做到这点,所有的Kafka节点都可以及时 ...
- 如何设计Kafka?
著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:Sugar Su链接:http://zhuanlan.zhihu.com/ms15213/20545422来源:知乎 此文稿来 ...
随机推荐
- DirectX Sample-ConfigSystem中采用配置文件进行游戏设置
这个例子是一个撞球系统,碰撞部分也值得学习,不过最重要的还是其配置部分,配置文件为config.txt,其中包括: Requirements:所需配置 propertyset:预定义的设置,通过名字引 ...
- VMware vSphere 服务器虚拟化之二十七桌面虚拟化之View中使用Thinapp软件虚拟化
VMware vSphere 服务器虚拟化之二十七桌面虚拟化之View中使用Thinapp软件虚拟化 VMware ThinApp 应用程序虚拟化软件是无代理解决方案,通过将应用程序隔离并封装为EXE ...
- 配置JVM内存 查看内存工具
一.配置JVM内存 1.配置JVM内存的參数有四个: -XmxJavaHeap最大值.默认值为物理内存的1/4.最佳设值应该视物理内存大小及计算机内其它内存开销而定. -XmsJavaHeap初始值, ...
- sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
在使用Hibernate的J2EE项目中,莫名其妙出现如上错误,既不报错,也不运行不论什么输出測试代码,更不返回结果. 经过排查,在方法里面引用的实体类和其映射文件属性个数不一致. 改动一致后,即解决 ...
- WPF换肤之八:创建3D浏览效果
原文:WPF换肤之八:创建3D浏览效果 上节中,我们展示了WPF中的异步以及界面线程交互的方式,使得应用程序的显示更加的流畅.这节我们主要讲解如何设计一个具有3D浏览效果的天气信息浏览器. 效果显示 ...
- Android---53---多线程下载
采用HttpURLConnection HttpURLConnection从继承URLConnection,它也可以被用来发送到指定的网站GET求 POST求. 办法: int getResponse ...
- cocos2d-x 3.1.1 学习笔记[2]Sprite 精灵
Sprite应该是用到最多的一个类吧.无法想像一个游戏没有精灵将怎样进行愉快的玩耍. Sprite继承于Node 和 TextureProtocol. Sprite是一个2d的图像. Sprite能够 ...
- 【Android】应用启动画面
几乎所有的Android应用程序都会有一个启动画面,展示自己的LOGO,本版信息,或者更人性化一点的,在很长的加载信息中,变换一些显示的文字等,让无聊的等待时间添加点调味剂. 具体实现来说,应该创建一 ...
- 使用ToggleButton和StackPanel+Border实现圆角开关按钮动画效果
<ToggleButton Height=" HorizontalAlignment="Left" Margin="138,122,0,0" N ...
- Matlab Error (Matrix dimensions must agree)
xOld =input('Enter initial guess: '); errortmp =2; counter =0; while (errortmp>10^-10) xNew =xOld ...