原文:https://cwiki.apache.org/confluence/display/KAFKA/Consumer+Group+Example

为什么使用High Level Consumer

  1. 在某些应用场景,我们希望通过多线程读取消息,而我们并不关心从Kafka消费消息的顺序,我们只关心数据能被消费即可。High Level 就是用于抽象这类消费动作的。

  2. 消息消费已Consumer Group为单位,每一个Consumer Group中能够有多个consumer。每一个consumer是一个线程,topic的每一个partition同一时候仅仅能被某一个consumer读 取,Consumer Group相应的每一个partition都有一个最新的offset的值,存储在zookeeper上的。所以不会出现反复消费的情况。

  3. 由于consumer的offerset并非实时的传送到zookeeper(通过配置来制定更新周期)。所以Consumer假设突然Crash,有可能会读取反复的信息

设计High Level Consumer

High Level Consumer 能够而且应该被使用在多线程的环境。线程模型中线程的数量(也代表group中consumer的数量)和topic的partition数量有关。以下列举一些规则:

  1. 当提供的线程数量多于partition的数量,则部分线程将不会接收到消息。
  2. 当提供的线程数量少于partition的数量,则部分线程将从多个partition接收消息。
  3. 当某个线程从多个partition接收消息时,不保证接收消息的顺序;可能出现从partition3接收5条消息。从partition4接收6条消息。接着又从partition3接收10条消息;
  4. 当加入很多其它线程时。会引起kafka做re-balance, 可能改变partition和线程的相应关系。
  5. 由于突然停止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的更多相关文章

  1. Consumer设计-high/low Level Consumer

    1 Producer和Consumer的数据推送拉取方式   Producer Producer通过主动Push的方式将消息发布到Broker n Consumer Consumer通过Pull从Br ...

  2. Kafka 学习笔记之 High Level Consumer相关参数

    High Level Consumer相关参数 自动管理offset auto.commit.enable = true auto.commit.interval.ms = 60*1000 手动管理o ...

  3. .net Kafka.Client多个Consumer Group对Topic消费不能完全覆盖研究总结(一)

    我们知道Kafka支持Consumer Group的功能,但是最近在应用Consumer Group时发现了一个Topic 的Partition不能100%覆盖的问题. 程序部署后,发现Kafka在p ...

  4. Kafka 学习笔记之 Consumer API

    Kafka提供了两种Consumer API High Level Consumer API Low Level Consumer API(Kafka诡异的称之为Simple Consumer API ...

  5. .net Kafka.Client多个Consumer Group对Topic消费不能完全覆盖研究总结(二)

    依据Partition和Consumer的Rebalance策略,找到Kafka.Client Rebalance代码块,还原本地环境,跟踪调试,发现自定义Consumer Group 的Consum ...

  6. Kafka客户端Producer与Consumer

    Kafka客户端Producer与Consumer 一.pom.xml 二.相关配置文件 producer.properties log4j.properties base.properties 三. ...

  7. 漫游Kafka设计篇之Producer和Consumer

    Kafka Producer 消息发送 producer直接将数据发送到broker的leader(主节点),不需要在多个节点进行分发.为了帮助producer做到这点,所有的Kafka节点都可以及时 ...

  8. 漫游Kafka设计篇之Producer和Consumer(4)

    Kafka Producer 消息发送 producer直接将数据发送到broker的leader(主节点),不需要在多个节点进行分发.为了帮助producer做到这点,所有的Kafka节点都可以及时 ...

  9. 如何设计Kafka?

    著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:Sugar Su链接:http://zhuanlan.zhihu.com/ms15213/20545422来源:知乎 此文稿来 ...

随机推荐

  1. VS调试技巧之附加进程

    用过VS一段时间的程序猿们相信都有过这种调试经历:每次按下F5进行断点调试时,都要等待好长时间:先让解决方式编译通过,然后启动VS自带的简版IIS作为server启动,进而开启浏览器,最后进行对应的操 ...

  2. Unity3D发布WebPlayer时Failed to download data file解决方案

    今天发布WebPlayer时, 发现直接打开html是可以正常运行的, 但是通过iis访问的话就会报错: Failed to download data file. 一开始以为是防火墙, 后来发现不是 ...

  3. e​c​s​h​o​p​模​板​ l​b​i​文​件

    Ecshop根目录/ |->其它目录|->themes |->例:default (模板项目目录) |->images                             ...

  4. poj 2992 Divisors 整数分解

    设m=C(n,k)=n!/((n-k)!*k!) 问题:求m的因数的个数 将m分解质因数得到 p1有a1个 p2有a2个 .... 因为每一个质因数能够取0~ai个(所有取0就是1,所有取ai就是m) ...

  5. 使用scipy进行聚类

    近期做图像的时候,突然有个idea,须要进行聚类,事实上算法非常easy,可是当时非常急.就直接使用了scipy的cluster. 使用起来事实上非常easy,可是中文的文章非常少,所以就简单的介绍一 ...

  6. 【译】手动处理Team Foundation Server 2010 数据仓库和分析服务数据库

    原贴地址:Manually Processing the Team Foundation Server 2010 Data Warehouse and Analysis Services Databa ...

  7. 软件測试系统文章(文件夹&amp;链接在此)

    前言 我会在此账号上写一系列关于软件測试的文章,故在此置顶软件測试系列文章的文件夹和链接,以方便大家阅读! 文件夹 软件測试系列之入门篇(一) 软件測试系列之了解篇(二) 软件測试系列之黑白盒(三) ...

  8. 鸟书shell 学习笔记(一) shell专注于概念和命令

    变量   variableName=value 等号左右不能有空格 变量内容有空格须要用"或者'括起来,可是 v="hello $name" $保持原有功能,单引號则不行 ...

  9. shell split分析日志文件

    在处理的文件comment有如下格式: ............................ xxx.xxx.10.59 db1059 mynbdpdatadb.idc4. dbname R620 ...

  10. Springmvc +JNDI 在Tomcat下 配置数据源(转)

    一.             简介 jndi(Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API.命名服务 ...