设计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来源:知乎 此文稿来 ...
随机推荐
- hdu4714(树形dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4714 题意:给你一棵树,,其中每去掉一条边或加一条边的代价均为1,让你求出将其变成一个圆的最小代价. ...
- poj1849(求树的直径)
题目链接:http://poj.org/problem?id=1849 题意:有一颗n个结点的带权的无向树, 在s结点放两个机器人, 这两个机器人会把树的每条边都走一遍, 但是最后机器人不要求回到出发 ...
- Nginx对某个文件夹或整个站点进行登录认证的方法
比方要对 站点文件夹下的 test 文件夹 进行加密认证 首先须要在opt 的主文件夹中 /opt/ 创建一个新文件 htpasswd 此文件的书写格式是 username:password 每行一个 ...
- 【转向Javascript系列】深入理解Generators
随着Javascript语言的发展,ES6规范为我们带来了许多新的内容,其中生成器Generators是一项重要的特性.利用这一特性,我们可以简化迭代器的创建,更加令人兴奋的,是Generators允 ...
- linux tomcat部署含有matlab画图打包的java web程序
首先说下问题:matlab可以把相关算法代码打包成jar文件共java调用,本例使用的jar文件的作用是画图并保存,然后部署在linux的tomcat中进行发布.这里出现了一个问题,具体如下:linu ...
- 在mysql数据库中关于日期时间字段的处理
在mysql数据库中关于日期时间字段的处理 在开发中,日期时间字段一般有如下几种设计 假设要获取2013-08-15日到2013-08-16日之间的记录 1. 直接使用日期时间类字段 相关sql语句如 ...
- windows phone 7 定位(获取经纬度),然后找到经纬度所在的位置(城市信息)
原文:windows phone 7 定位(获取经纬度),然后找到经纬度所在的位置(城市信息) 前几天做项目用到, 代码贴给大家. /// <summary> /// 获取当前位置的经纬度 ...
- PHP_保留两位小数而且四舍五入_保留两位小数而且不四舍五入
php保留两位小数而且四舍五入 $num = 123213.666666; echo sprintf("%.2f", $num); php保留两位小数而且不四舍五入 $num = ...
- WPF Delegate委托整理
那啥,是从这里整理出来的,感谢Rising_Sun,整理的过于简单,看不明白的戳这里 using System; using System.Collections.Generic; using Sys ...
- 一个Jquery特效(转)
见证花开!!码上有花 先看效果 尝试点击,IE9+ 画心 清空 ... 请自由点击画布 创意来自于网络 可搜搜[程序员表白] 看上去像是[当耐特]的作品的加工版本 代码 当然要自己写了 能力有限, ...