大数据生态系统基础:Apache Kafka基础(三):最新kafka编程入门:Consumer

 生产者将信息输入到集群中, 那么消费者就要能从集群中取出所需要的信息。

        主要的类就是: KafkaConsumer<K,V>

一、原理

       Kafka的一个分区的每一个记录保持一个数值偏移。这个偏移量作为该分区内记录的惟一标识符,并表示该分区中的使用者的位置。例如,处于位置5的消费者使用偏移量0到4的记录,然后将使用偏移量5来接收记录。

    消费者api提供了覆盖各种消费用例的灵活性。

二、自动位移提交

     以下是完成的程序案例

[java]  view plain  copy
  1. package wangxn.testConsumer;  
  2.   
  3.   
  4. import java.util.Collections;  
  5. import java.util.Properties;  
  6.   
  7.   
  8. import org.apache.kafka.clients.consumer.ConsumerRecord;  
  9. import org.apache.kafka.clients.consumer.ConsumerRecords;  
  10. import org.apache.kafka.clients.consumer.KafkaConsumer;  
  11. import org.apache.kafka.clients.consumer.ConsumerConfig;  
  12. public class autoConsumer {  
  13. <span style="white-space:pre;"> </span>private static KafkaConsumer<String, String> consumer;  
  14. <span style="white-space:pre;"> </span>  
  15. <span style="white-space:pre;"> </span>public static void main(String[] args) {  
  16. <span style="white-space:pre;">     </span>// TODO Auto-generated method stub  
  17. <span style="white-space:pre;">     </span>Properties props = new Properties();  
  18. <span style="white-space:pre;"> </span>     props.put("bootstrap.servers""mymac:9092");  
  19. <span style="white-space:pre;"> </span>     props.put("group.id""DemoConsumer");  
  20. <span style="white-space:pre;"> </span>     props.put("enable.auto.commit""true");  
  21. <span style="white-space:pre;"> </span>     props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "1000");  
  22. <span style="white-space:pre;"> </span>     props.put("auto.commit.interval.ms""30000");  
  23. <span style="white-space:pre;"> </span>     props.put("key.deserializer""org.apache.kafka.common.serialization.StringDeserializer");  
  24. <span style="white-space:pre;"> </span>     props.put("value.deserializer""org.apache.kafka.common.serialization.StringDeserializer");  
  25. <span style="white-space:pre;"> </span>       
  26. <span style="white-space:pre;"> </span>     //consumer.subscribe(Arrays.asList("foo", "bar"));  
  27. <span style="white-space:pre;"> </span>     consumer = new KafkaConsumer<>(props);  
  28. <span style="white-space:pre;"> </span>    
  29. <span style="white-space:pre;"> </span>       
  30. <span style="white-space:pre;"> </span>     while (true) {  
  31. <span style="white-space:pre;"> </span>    <span style="white-space:pre;">    </span>      
  32. <span style="white-space:pre;"> </span>    <span style="white-space:pre;">    </span>     consumer.subscribe(Collections.singletonList("my-topic"));  
  33. <span style="white-space:pre;"> </span>         ConsumerRecords<String, String> records = consumer.poll(1000);  
  34. <span style="white-space:pre;"> </span>         for (ConsumerRecord<String, String> record : records)   
  35. <span style="white-space:pre;"> </span>             System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());  
  36. <span style="white-space:pre;"> </span>         //consumer.close();  
  37. <span style="white-space:pre;"> </span>     }  
  38. <span style="white-space:pre;"> </span>          
  39. <span style="white-space:pre;"> </span>}  
  40.   
  41.   
  42. }  
       其中,设置   enable.auto.commit  为 true, 就是偏移量可以按照一定的频率自动提交。 auto.commit.interval.ms  就是用来设置频率的。

        程序是不断运行的。运行结果就是:

         producer 端发送消息:

$ kafka-console-producer.sh --broker-list mymac:9092 --topic my-topic

扫描二维码关注公众号,回复: 1110693 查看本文章

>dajia
>ceshi
>ok, quickly
>

本程序将接收消息:


 三、手动偏移量控制

          这将设置 enable.auto.commit 为 false

         用户不必依赖于使用者定期提交消耗的偏移量,还可以控制记录何时被视为消耗,从而提交他们的偏移量。当消息的消费与某些处理逻辑结合在一起时,这是很有用的,因此在完成处理之前,不应该将消息视为消费。

[java]  view plain  copy
  1. Properties props = new Properties();  
  2. props.put("bootstrap.servers""localhost:9092");  
  3. props.put("group.id""test");  
  4. props.put("enable.auto.commit""false");  
  5. props.put("key.deserializer""org.apache.kafka.common.serialization.StringDeserializer");  
  6. props.put("value.deserializer""org.apache.kafka.common.serialization.StringDeserializer");  
  7. KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);  
  8. consumer.subscribe(Arrays.asList("foo""bar"));  
  9. final int minBatchSize = 200;  
  10. List<ConsumerRecord<String, String>> buffer = new ArrayList<>();  
  11. while (true) {  
  12.     ConsumerRecords<String, String> records = consumer.poll(100);  
  13.     for (ConsumerRecord<String, String> record : records) {  
  14.         buffer.add(record);  
  15.     }  
  16.     if (buffer.size() >= minBatchSize) {  
  17.         insertIntoDb(buffer);  
  18.         consumer.commitSync();  
  19.         buffer.clear();  
  20.     }  
  21. }  

       在本例中,我们将使用一批记录,并在内存中对它们进行批处理。当我们有足够的记录时,我们将把它们插入到一个数据库中。如果我们允许在前面的示例中使用补偿来进行自动提交,那么在Poll 中返回给用户之后,记录将被认为是消耗的。这样,我们的进程在批处理记录之后可能会失败,但是在它们被插入到数据库之前。
为了避免这种情况,我们将在将相应的记录插入到数据库之后手工提交补偿。这使我们精确地控制了记录被认为是消耗的时间。这就产生了相反的可能性:在插入到数据库之后,进程可能会失败,但是在提交之前(尽管可能只有几毫秒,但这是有可能的)。在这种情况下,接管消费的过程将消耗最后一次提交的偏移量,并将重复最后一批数据的插入。使用这种方式,Kafka提供了通常被称为“最少一次”的交付保证,因为每一次记录都可能被交付一次,但在失败案例中可能会被重复。

     注意:使用自动偏移量提交也可以给您“至少一次”的交付,但是需求是您必须在任何后续调用之前,或者在关闭客户之前,使用从每个调用返回的所有数据(给 Poll)。如果您没有执行这两种操作,那么就有可能被提交的偏移量超出所消耗的位置,从而导致丢失的记录。使用手动补偿控制的优点是,当记录被认为是“消耗”时,您可以直接控制。

             上面的例子是用 CommitSync 去标记所有已经提交的接收记录。在某些情况下,您可能希望通过显式地指定偏移量来更好地控制哪些记录被提交。在下面的例子中,我们在处理完每个分区中的记录之后,提交了偏移量。

    

[java]  view plain  copy
  1. try {  
  2.         while(running) {  
  3.             ConsumerRecords<String, String> records = consumer.poll(Long.MAX_VALUE);  
  4.             for (TopicPartition partition : records.partitions()) {  
  5.                 List<ConsumerRecord<String, String>> partitionRecords = records.records(partition);  
  6.                 for (ConsumerRecord<String, String> record : partitionRecords) {  
  7.                     System.out.println(record.offset() + ": " + record.value());  
  8.                 }  
  9.                 long lastOffset = partitionRecords.get(partitionRecords.size() - 1).offset();  
  10.                 consumer.commitSync(Collections.singletonMap(partition, new OffsetAndMetadata(lastOffset + 1)));  
  11.             }  
  12.         }  
  13.     } finally {  
  14.       consumer.close();  
  15.     }  
注意:提交的偏移量应该始终是应用程序将要读取的下一条消息的偏移量。因此,当调用   commitSync(offsets)   时,您应该将一个添加到处理的最后一条消息的偏移量。


四、手动分配 Partition

     String topic = "foo";
     TopicPartition partition0 = new TopicPartition(topic, 0);
     TopicPartition partition1 = new TopicPartition(topic, 1);
     consumer.assign(Arrays.asList(partition0, partition1));

五、采用多线程来进行处理

         下面是完整的程序,不解释。

        

[java]  view plain  copy
  1. package wangxn.testkafka;  
  2.   
  3. import kafka.utils.ShutdownableThread;  
  4.   
  5.   
  6. import org.apache.kafka.clients.consumer.ConsumerConfig;  
  7. import org.apache.kafka.clients.consumer.ConsumerRecord;  
  8. import org.apache.kafka.clients.consumer.ConsumerRecords;  
  9. import org.apache.kafka.clients.consumer.KafkaConsumer;  
  10.   
  11. import java.util.Collections;  
  12. import java.util.Properties;  
  13.   
  14. public class myConsumer extends ShutdownableThread {  
  15.   
  16.   
  17.     private final KafkaConsumer<Integer, String> consumer;  
  18.         private final String topic;  
  19.   
  20.         public myConsumer(String topic) {  
  21.             super("KafkaConsumerExample"false);  
  22.             Properties props = new Properties();  
  23.             props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "mymac:9092");  
  24.             props.put(ConsumerConfig.GROUP_ID_CONFIG, "DemoConsumer");  
  25.             props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true");  
  26.             props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "1000");  
  27.             props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "30000");  
  28.             props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.IntegerDeserializer");  
  29.             props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");  
  30.   
  31.             consumer = new KafkaConsumer<Integer,String>(props);  
  32.             this.topic = topic;  
  33.           
  34.         }  
  35.   
  36.         @Override  
  37.         public void doWork() {  
  38.           
  39.             consumer.subscribe(Collections.singletonList(this.topic));  
  40.            // System.err.println("consumer.subscribe!");  
  41.             ConsumerRecords<Integer, String> records = consumer.poll(3000);  
  42.             
  43.             for (ConsumerRecord<Integer, String> record : records)   
  44.                 System.out.println("Received message: (" + record.key() + ", " + record.value() + ") at offset " + record.offset());  
  45.               
  46.         }  
  47.   
  48.         @Override  
  49.         public String name() {  
  50.             return null;  
  51.         }  
  52.   
  53.         @Override  
  54.         public boolean isInterruptible() {  
  55.             return false;  
  56.         }  
  57.   
  58. }  

猜你喜欢

转载自blog.csdn.net/qq_36838191/article/details/80453618