Kafka --Kafka编程实战-java客户端开发例子

本入门教程,涵盖Kafka核心内容,通过实例和大量图表,帮助学习者理解,任何问题欢迎留言。

目录:

  • kafka简介
  • kafka安装和使用
  • kafka核心概念
  • kafka核心组件和流程--控制器
  • kafka核心组件和流程--协调器
  • kafka核心组件和流程--日志管理器
  • kafka核心组件和流程--副本管理器
  • kafka编程实战

本章通过实际例子,讲解了如何使用java进行kafka开发。

 

准备

添加依赖:


 
 
   
   
   
   
  1. <dependency>
  2. <groupId>org.apache.kafka groupId>
  3. <artifactId>kafka-clients artifactId>
  4. <version>2.0.0 version>
  5. dependency>

创建主题

下面是创建主题的代码:


 
 
   
   
   
   
  1. public class TopicProcessor {
  2. private static final String ZK_CONNECT= "localhost:2181";
  3. private static final int SESSION_TIME_OUT= 30000;
  4. private static final int CONNECT_OUT= 30000;
  5. public static void createTopic(String topicName,int partitionNumber,int replicaNumber,Properties properties){
  6. ZkUtils zkUtils = null;
  7. try{
  8. zkUtils=ZkUtils.apply(ZK_CONNECT,SESSION_TIME_OUT,CONNECT_OUT, JaasUtils.isZkSecurityEnabled());
  9. if(!AdminUtils.topicExists(zkUtils,topicName)){
  10. AdminUtils.createTopic(zkUtils,topicName,partitionNumber,replicaNumber,properties,AdminUtils.createTopic$ default$ 6());
  11. }
  12. } catch (Exception e){
  13. e.printStackTrace();
  14. } finally {
  15. zkUtils.close();
  16. }
  17. }
  18. public static void main(String[] args){
  19. createTopic( "javatopic", 1, 1, new Properties());
  20. }
  21. }

首先定义了zookeeper相关连接信息。然后在createTopic中,先初始化ZkUtils,和zookeeper交互依赖于它。然后通过AdminUtils先判断是否存在你要创建的主题,如果不存在,则通过createTopic方法进行创建。传入参数包括主题名称,分区数量,副本数量等。

 

生产者生产消息

生产者生产消息代码如下:


 
 
   
   
   
   
  1. public class MessageProducer {
  2. private static final String TOPIC= "education-info";
  3. private static final String BROKER_LIST= "localhost:9092";
  4. private static KafkaProducer producer = null;
  5. static{
  6. Properties configs = initConfig();
  7. producer = new KafkaProducer(configs);
  8. }
  9. private static Properties initConfig(){
  10. Properties properties = new Properties();
  11. properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,BROKER_LIST);
  12. properties.put(ProducerConfig.ACKS_CONFIG, "all");
  13. properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
  14. properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,StringSerializer.class.getName());
  15. return properties;
  16. }
  17. public static void main(String[] args){
  18. try{
  19. String message = "hello world";
  20. ProducerRecord record = new ProducerRecord(TOPIC,message);
  21. producer.send(record, new Callback() {
  22. @Override
  23. public void onCompletion(RecordMetadata metadata, Exception exception) {
  24. if( null==exception){
  25. System.out.println( "perfect!");
  26. }
  27. if( null!=metadata){
  28. System.out.print( "offset:"+metadata.offset()+ ";partition:"+metadata.partition());
  29. }
  30. }
  31. }).get();
  32. } catch (Exception e){
  33. e.printStackTrace();
  34. } finally {
  35. producer.close();
  36. }
  37. }
  38. }

1、首先初始化KafkaProducer对象。

producer = new KafkaProducer(configs);
 
 
   
   
   
   

2、创建要发送的消息对象。

ProducerRecord record = new ProducerRecord(TOPIC,message);
 
 
   
   
   
   

3、通过producer的send方法,发送消息

4、发送消息时,可以通过回调函数,取得消息发送的结果。异常发生时,对异常进行处理。

初始化producer时候,需要注意下面属性设置:

properties.put(ProducerConfig.ACKS_CONFIG,"all");
 
 
   
   
   
   

这里有三种值可供选择:

  • 0,不等服务器响应,直接返回发送成功。速度最快,但是丢了消息是无法知道的
  • 1,leader副本收到消息后返回成功
  • all,所有参与的副本都复制完成后返回成功。这样最安全,但是延迟最高。

 

消费者消费消息

我们直接看代码


 
 
   
   
   
   
  1. public class MessageConsumer {
  2. private static final String TOPIC= "education-info";
  3. private static final String BROKER_LIST= "localhost:9092";
  4. private static KafkaConsumer kafkaConsumer = null;
  5. static {
  6. Properties properties = initConfig();
  7. kafkaConsumer = new KafkaConsumer(properties);
  8. kafkaConsumer.subscribe(Arrays.asList(TOPIC));
  9. }
  10. private static Properties initConfig(){
  11. Properties properties = new Properties();
  12. properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,BROKER_LIST);
  13. properties.put(ConsumerConfig.GROUP_ID_CONFIG, "test");
  14. properties.put(ConsumerConfig.CLIENT_ID_CONFIG, "test");
  15. properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
  16. properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,StringDeserializer.class.getName());
  17. return properties;
  18. }
  19. public static void main(String[] args){
  20. try{
  21. while( true){
  22. ConsumerRecords records = kafkaConsumer.poll( 100);
  23. for(ConsumerRecord record:records){
  24. try{
  25. System.out.println(record.value());
  26. } catch(Exception e){
  27. e.printStackTrace();
  28. }
  29. }
  30. }
  31. } catch(Exception e){
  32. e.printStackTrace();
  33. } finally {
  34. kafkaConsumer.close();
  35. }
  36. }
  37. }

代码逻辑如下:

1、初始化消费者KafkaConsumer,并订阅主题。


 
 
   
   
   
   
  1. kafkaConsumer = new KafkaConsumer(properties);
  2. kafkaConsumer.subscribe(Arrays.asList(TOPIC));

2、循环拉取消息

ConsumerRecords records = kafkaConsumer.poll(100);
 
 
   
   
   
   

poll方法传入的参数100,是等待broker返回数据的时间,如果超过100ms没有响应,则不再等待。

3、拉取回消息后,循环处理。


 
 
   
   
   
   
  1. for(ConsumerRecord record:records){
  2. try{
  3. System.out.println(record.value());
  4. } catch(Exception e){
  5. e.printStackTrace();
  6. }
  7. }

消费相关代码比较简单,不过这个版本没有处理偏移量提交。学习过第四章-协调器相关的同学应该还记得偏移量提交的问题。我曾说过最佳实践是同步和异步提交相结合,同时在特定的时间点,比如再均衡前进行手动提交。

加入偏移量提交,需要做如下修改:

1、enable.auto.commit设置为false

2、消费代码如下:


 
 
   
   
   
   
  1. public static void main(String[] args){
  2. try{
  3. while( true){
  4. ConsumerRecords records =
  5. kafkaConsumer.poll( 100);
  6. for(ConsumerRecord record:records){
  7. try{
  8. System.out.println(record.value());
  9. } catch(Exception e){
  10. e.printStackTrace();
  11. }
  12. }
  13. kafkaConsumer.commitAsync();
  14. }
  15. } catch(Exception e){
  16. e.printStackTrace();
  17. } finally {
  18. try{
  19. kafkaConsumer.commitSync();
  20. } finally {
  21. kafkaConsumer.close();
  22. }
  23. }
  24. }

3、订阅消息时,实现再均衡的回调方法,在此方法中手动提交偏移量


 
 
   
   
   
   
  1. kafkaConsumer.subscribe(Arrays.asList(TOPIC), new ConsumerRebalanceListener() {
  2. @Override
  3. public void onPartitionsRevoked(Collection partitions) {
  4. //再均衡之前和消费者停止读取消息之后调用
  5. kafkaConsumer.commitSync(currentOffsets);
  6. }
  7. });

通过以上三步,我们把自动提交偏移量改为了手动提交。正常消费时,异步提交kafkaConsumer.commitAsync()。即使偶尔失败,也会被后续成功的提交覆盖掉。而在发生异常的时候,手动提交 kafkaConsumer.commitSync()。此外在步骤3中,我们通过实现再均衡时的回调方法,手动同步提交偏移量,确保了再均衡前偏移量提交成功。

以上面的最佳实践提交偏移量,既能保证消费时较高的效率,又能够尽量避免重复消费。不过由于重复消费无法100%避免,消费逻辑需要自己处理重复消费的判断。

至此,本系列kafka轻松学教程也就完结了。教程涵盖了Kafka大部分的内容,但没有涉及到流相关的内容。Kafka实现的部分细节也没有做过多的讲解。学习完本教程,如果你能够对kafka的原理有较为深刻的理解,并且能够上手开发程序,目的就已经达到了。如果想继续探寻Kafka工作的细节,可以再看更为深入的资料。相信通过此教程打好基础,再深入学习kafka也会更为容易!

你可能感兴趣的:(Kafka)