Kafka Consumer的底层API- SimpleConsumer

Kafka Consumer的底层API- SimpleConsumer


1.Kafka提供了两套API给Consumer

  1. The high-level Consumer API
  2. The SimpleConsumer API     
第一种高度抽象的Consumer API,它使用起来简单、方便,但是对于某些特殊的需求我们可能要用到第二种更底层的API,那么先介绍下第二种API能够帮助我们做哪些事情
  • 一个消息读取多次
  • 在一个处理过程中只消费Partition其中的一部分消息
  • 添加事务管理机制以保证消息被处理且仅被处理一次

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

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

3.使用SimpleConsumer的步骤

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

4.代码实例



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


转载于:https://my.oschina.net/u/1377774/blog/469271

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值