问题导读

1.Kafka如何实现和Consumer之间的交互?
2.使用SimpleConsumer有哪些弊端呢?

1.Kafka提供了两套API给Consumer

  • The high-level Consumer API
  • The SimpleConsumer API

第一种高度抽象的Consumer API,它使用起来简单、方便,但是对于某些特殊的需求我们可能要用到第二种更底层的API,那么先介绍下第二种API能够帮助我们做哪些事情

  • 一个消息读取多次
  • 在一个处理过程中只消费Partition其中的一部分消息
  • 添加事务管理机制以保证消息被处理且仅被处理一次

2.使用SimpleConsumer有哪些弊端呢?

  • 必须在程序中跟踪offset值
  • 必须找出指定Topic Partition中的lead broker
  • 必须处理broker的变动

3.使用SimpleConsumer的步骤

  • 从所有活跃的broker中找出哪个是指定Topic Partition中的leader broker
  • 找出指定Topic Partition中的所有备份broker
  • 构造请求
  • 发送请求查询数据
  • 处理leader broker变更

4.代码实例

  1. package bonree.consumer;
  2. import java.nio.ByteBuffer;
  3. import java.util.ArrayList;
  4. import java.util.Collections;
  5. import java.util.HashMap;
  6. import java.util.List;
  7. import java.util.Map;
  8. import kafka.api.FetchRequest;
  9. import kafka.api.FetchRequestBuilder;
  10. import kafka.api.PartitionOffsetRequestInfo;
  11. import kafka.common.ErrorMapping;
  12. import kafka.common.TopicAndPartition;
  13. import kafka.javaapi.FetchResponse;
  14. import kafka.javaapi.OffsetResponse;
  15. import kafka.javaapi.PartitionMetadata;
  16. import kafka.javaapi.TopicMetadata;
  17. import kafka.javaapi.TopicMetadataRequest;
  18. import kafka.javaapi.consumer.SimpleConsumer;
  19. import kafka.message.MessageAndOffset;
  20. public class SimpleExample {
  21. private List<String> m_replicaBrokers = new ArrayList<String>();
  22. public SimpleExample() {
  23. m_replicaBrokers = new ArrayList<String>();
  24. }
  25. public static void main(String args[]) {
  26. SimpleExample example = new SimpleExample();
  27. // 最大读取消息数量
  28. long maxReads = Long.parseLong("3");
  29. // 要订阅的topic
  30. String topic = "mytopic";
  31. // 要查找的分区
  32. int partition = Integer.parseInt("0");
  33. // broker节点的ip
  34. List<String> seeds = new ArrayList<String>();
  35. seeds.add("192.168.4.30");
  36. seeds.add("192.168.4.31");
  37. seeds.add("192.168.4.32");
  38. // 端口
  39. int port = Integer.parseInt("9092");
  40. try {
  41. example.run(maxReads, topic, partition, seeds, port);
  42. } catch (Exception e) {
  43. System.out.println("Oops:" + e);
  44. e.printStackTrace();
  45. }
  46. }
  47. public void run(long a_maxReads, String a_topic, int a_partition, List<String> a_seedBrokers, int a_port) throws Exception {
  48. // 获取指定Topic partition的元数据
  49. PartitionMetadata metadata = findLeader(a_seedBrokers, a_port, a_topic, a_partition);
  50. if (metadata == null) {
  51. System.out.println("Can't find metadata for Topic and Partition. Exiting");
  52. return;
  53. }
  54. if (metadata.leader() == null) {
  55. System.out.println("Can't find Leader for Topic and Partition. Exiting");
  56. return;
  57. }
  58. String leadBroker = metadata.leader().host();
  59. String clientName = "Client_" + a_topic + "_" + a_partition;
  60. SimpleConsumer consumer = new SimpleConsumer(leadBroker, a_port, 100000, 64 * 1024, clientName);
  61. long readOffset = getLastOffset(consumer, a_topic, a_partition, kafka.api.OffsetRequest.EarliestTime(), clientName);
  62. int numErrors = 0;
  63. while (a_maxReads > 0) {
  64. if (consumer == null) {
  65. consumer = new SimpleConsumer(leadBroker, a_port, 100000, 64 * 1024, clientName);
  66. }
  67. FetchRequest req = new FetchRequestBuilder().clientId(clientName).addFetch(a_topic, a_partition, readOffset, 100000).build();
  68. FetchResponse fetchResponse = consumer.fetch(req);
  69. if (fetchResponse.hasError()) {
  70. numErrors++;
  71. // Something went wrong!
  72. short code = fetchResponse.errorCode(a_topic, a_partition);
  73. System.out.println("Error fetching data from the Broker:" + leadBroker + " Reason: " + code);
  74. if (numErrors > 5)
  75. break;
  76. if (code == ErrorMapping.OffsetOutOfRangeCode()) {
  77. // We asked for an invalid offset. For simple case ask for
  78. // the last element to reset
  79. readOffset = getLastOffset(consumer, a_topic, a_partition, kafka.api.OffsetRequest.LatestTime(), clientName);
  80. continue;
  81. }
  82. consumer.close();
  83. consumer = null;
  84. leadBroker = findNewLeader(leadBroker, a_topic, a_partition, a_port);
  85. continue;
  86. }
  87. numErrors = 0;
  88. long numRead = 0;
  89. for (MessageAndOffset messageAndOffset : fetchResponse.messageSet(a_topic, a_partition)) {
  90. long currentOffset = messageAndOffset.offset();
  91. if (currentOffset < readOffset) {
  92. System.out.println("Found an old offset: " + currentOffset + " Expecting: " + readOffset);
  93. continue;
  94. }
  95. readOffset = messageAndOffset.nextOffset();
  96. ByteBuffer payload = messageAndOffset.message().payload();
  97. byte[] bytes = new byte[payload.limit()];
  98. payload.get(bytes);
  99. System.out.println(String.valueOf(messageAndOffset.offset()) + ": " + new String(bytes, "UTF-8"));
  100. numRead++;
  101. a_maxReads--;
  102. }
  103. if (numRead == 0) {
  104. try {
  105. Thread.sleep(1000);
  106. } catch (InterruptedException ie) {
  107. }
  108. }
  109. }
  110. if (consumer != null)
  111. consumer.close();
  112. }
  113. public static long getLastOffset(SimpleConsumer consumer, String topic, int partition, long whichTime, String clientName) {
  114. TopicAndPartition topicAndPartition = new TopicAndPartition(topic, partition);
  115. Map<TopicAndPartition, PartitionOffsetRequestInfo> requestInfo = new HashMap<TopicAndPartition, PartitionOffsetRequestInfo>();
  116. requestInfo.put(topicAndPartition, new PartitionOffsetRequestInfo(whichTime, 1));
  117. kafka.javaapi.OffsetRequest request = new kafka.javaapi.OffsetRequest(requestInfo, kafka.api.OffsetRequest.CurrentVersion(), clientName);
  118. OffsetResponse response = consumer.getOffsetsBefore(request);
  119. if (response.hasError()) {
  120. System.out.println("Error fetching data Offset Data the Broker. Reason: " + response.errorCode(topic, partition));
  121. return 0;
  122. }
  123. long[] offsets = response.offsets(topic, partition);
  124. return offsets[0];
  125. }
  126. /**
  127. * @param a_oldLeader
  128. * @param a_topic
  129. * @param a_partition
  130. * @param a_port
  131. * @return String
  132. * @throws Exception
  133. *             找一个leader broker
  134. */
  135. private String findNewLeader(String a_oldLeader, String a_topic, int a_partition, int a_port) throws Exception {
  136. for (int i = 0; i < 3; i++) {
  137. boolean goToSleep = false;
  138. PartitionMetadata metadata = findLeader(m_replicaBrokers, a_port, a_topic, a_partition);
  139. if (metadata == null) {
  140. goToSleep = true;
  141. } else if (metadata.leader() == null) {
  142. goToSleep = true;
  143. } else if (a_oldLeader.equalsIgnoreCase(metadata.leader().host()) && i == 0) {
  144. // first time through if the leader hasn't changed give
  145. // ZooKeeper a second to recover
  146. // second time, assume the broker did recover before failover,
  147. // or it was a non-Broker issue
  148. //
  149. goToSleep = true;
  150. } else {
  151. return metadata.leader().host();
  152. }
  153. if (goToSleep) {
  154. try {
  155. Thread.sleep(1000);
  156. } catch (InterruptedException ie) {
  157. }
  158. }
  159. }
  160. System.out.println("Unable to find new leader after Broker failure. Exiting");
  161. throw new Exception("Unable to find new leader after Broker failure. Exiting");
  162. }
  163. private PartitionMetadata findLeader(List<String> a_seedBrokers, int a_port, String a_topic, int a_partition) {
  164. PartitionMetadata returnMetaData = null;
  165. loop: for (String seed : a_seedBrokers) {
  166. SimpleConsumer consumer = null;
  167. try {
  168. consumer = new SimpleConsumer(seed, a_port, 100000, 64 * 1024, "leaderLookup");
  169. List<String> topics = Collections.singletonList(a_topic);
  170. TopicMetadataRequest req = new TopicMetadataRequest(topics);
  171. kafka.javaapi.TopicMetadataResponse resp = consumer.send(req);
  172. List<TopicMetadata> metaData = resp.topicsMetadata();
  173. for (TopicMetadata item : metaData) {
  174. for (PartitionMetadata part : item.partitionsMetadata()) {
  175. if (part.partitionId() == a_partition) {
  176. returnMetaData = part;
  177. break loop;
  178. }
  179. }
  180. }
  181. } catch (Exception e) {
  182. System.out.println("Error communicating with Broker [" + seed + "] to find Leader for [" + a_topic + ", " + a_partition + "] Reason: " + e);
  183. } finally {
  184. if (consumer != null)
  185. consumer.close();
  186. }
  187. }
  188. if (returnMetaData != null) {
  189. m_replicaBrokers.clear();
  190. for (kafka.cluster.Broker replica : returnMetaData.replicas()) {
  191. m_replicaBrokers.add(replica.host());
  192. }
  193. }
  194. return returnMetaData;
  195. }
  196. }

转自:http://www.aboutyun.com/thread-11117-1-1.html

Kafka详解五:Kafka Consumer的底层API- SimpleConsumer的更多相关文章

  1. kafka详解(一)--kafka是什么及怎么用

    kafka是什么 在回答这个问题之前,我们需要先了解另一个东西--event streaming. 什么是event streaming 我觉得,event streaming 是一个动态的概念,它描 ...

  2. kafka详解(二)--kafka为什么快

    前言 Kafka 有多快呢?我们可以使用 OpenMessaging Benchmark Framework 测试框架方便地对 RocketMQ.Pulsar.Kafka.RabbitMQ 等消息系统 ...

  3. .NET DLL 保护措施详解(五)常规条件下的破解

    为了证实在常规手段破解下能有效保护程序核心功能(演示版本对AES加解密算法及数据库的密钥(一段字符串)进行了保护),特对此DLL保护思路进行相应的测试,包含了反编译及反射测试,看是否能得到AES加解密 ...

  4. 转:Windows下的PHP开发环境搭建——PHP线程安全与非线程安全、Apache版本选择,及详解五种运行模式。

    原文来自于:http://www.ituring.com.cn/article/128439 Windows下的PHP开发环境搭建——PHP线程安全与非线程安全.Apache版本选择,及详解五种运行模 ...

  5. python设计模式之迭代器与生成器详解(五)

    前言 迭代器是设计模式中的一种行为模式,它提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示.python提倡使用生成器,生成器也是迭代器的一种. 系列文章 python设计模 ...

  6. pika详解(五)登录认证及connectionParameters

    pika详解(五)登录认证及connectionParameters 本文链接:https://blog.csdn.net/comprel/article/details/94662916 版权 pi ...

  7. [转]人人网首页拖拽上传详解(HTML5 Drag&Drop、FileReader API、formdata)

    人人网首页拖拽上传详解(HTML5 Drag&Drop.FileReader API.formdata) 2011年12月11日 | 彬Go 上一篇:给力的 Google HTML5 训练营( ...

  8. 详解Java8的日期和时间API

    详解Java8的日期和时间API 在JDK1.0的时候,Java引入了java.util.Date来处理日期和时间:在JDK1.1的时候又引入了功能更强大的java.util.Calendar,但是C ...

  9. Kafka详解与总结(五)

    Kafka持久化 1. 概述 Kafka大量依赖文件系统去存储和缓存消息.对于硬盘有个传统的观念是硬盘总是很慢,这使很多人怀疑基于文件系统的架构能否提供优异的性能.实际上硬盘的快慢完全取决于使用它的方 ...

随机推荐

  1. windown安装bloomFilter

    个人博客:https://blog.sharedata.info/ 最近在研究python爬虫,需要在windown中安装bloomFilter来处理网页的去重问题,在window中安装python然 ...

  2. 《UNIX网络编程》 -- 第五章

    str_cli 和 str_echo 函数 需要先弄清楚 3.9 readn.writen 和 readline 函数 str_cli void str_cli(FILE *fp, int sockf ...

  3. 【转】mysql利用init-connect增加访问审计功能

    mysql的连接首先都是要通过init-connect初始化,然后连接到实例. 我们利用这一点,通过在init-connect的时候记录下用户的thread_id,用户名和用户地址实现db的访问审计功 ...

  4. 通过jdt解析spring mvc中url-类-方法的对应关系

    依赖 <dependencies> <dependency> <groupId>org.eclipse.jdt</groupId> <artifa ...

  5. Jquery获取dom上的绑定事件

    在1.8.0版本之前的写法: $.data(domObj,'events');//或者$('selector').data('events') 1.8.0及以后的写法: $._data(domObj, ...

  6. Python正则表达式基础

    1. 正则表达式基础 1.1. 简单介绍 正则表达式并不是Python的一部分.正则表达式是用于处理字符串的强大工具,拥有自己独特的语法以及一个独立的处理引擎,效率上可能不如str自带的方法,但功能十 ...

  7. ABAP f4帮助输入多个值

    *---------------------------------------------------------------------- * INITIALIZATION *---------- ...

  8. 剑指offer 面试67题

    面试67题: 题目: 链接:https://www.nowcoder.com/questionTerminal/1277c681251b4372bdef344468e4f26e?commentTags ...

  9. 如何配置一个路径,能够既适合Linux平台,又适合Windows平台,可以从这个路径中读取文件

    如何配置一个路径,能够既适合Linux平台,又适合Windows平台,可以从这个路径中读取文件? 目的:就是希望在项目的配置文件中配上一样的路径,不管协作者使用的是什么平台,都能够读到文件. 比如:L ...

  10. request doesn't contain a multipart/form-data or multipart/mixed stream ……

    有文件控件"file"的表单,在提交的时候,直接使用了ajax提交,结果报了一堆错,原来这个东东要提交表单,还要用post方式,最后更改为: $("#saveForm&q ...