【Kafka精进系列004】Spring Boot + Kafka消息生产与消费代码示例

在上两节中,我们分别在本地和Docker中安装启动了Kafka,并演示了Kafka消息的发送和接收过程。本节我们将我们基于Spring Boot和Kafka API来实现Kafka消息的生产与消费代码示例。

通过本文,你可以学到:

  • Kafka生产者异步发送API介绍;
  • Kafka生产者消息发送的代码实现;
  • Kafka生产者发送的消息不丢失的配置参数;
  • Kafka消费者常见的两种消费方案设计(单实例与多实例以及多线程消费);
  • Spring Boot整合Kafka实现Kafka生产与消费的完整过程

本文完整代码见My Github Link .

一、Kafka消息发送

首先需要说明的是,本文采用的是Kafka提供的消息发送和消费原生API。如果使用Spring-kafka提供的kafkaTemplate,使用方法也是一样的。

1、创建测试Topic、运行消费者

在Kafka消息发送消息之前,需要在本地先启动ZK、Kafka,并启动一个消费者用于测试。以本人为例,我在Docker端启动一个Kafka容器后,分别启动kafka server和一个消费者,如下:

(1)启动Kafka

(2)创建新的Topic用于测试

(3)运行一个消费者,用于测试消息的消费
【Kafka精进系列004】Spring Boot + Kafka消息生产与消费代码示例_第1张图片
没有报错表示环境搭建正常。

2、消息发送代码实现

Kafka消息发送的过程很简单,指定发送的Broker IP以及producer的一些参数后,就可以发送消息了。消息发送有同步和异步两种实现,下面我们来看下两种如何实现。

(1)Produce参数配置

application.yml

### Kafka
spring:
  kafka:
    bootstrap-servers: 192.168.1.199:9092

    #生产者的配置,大部分我们可以使用默认的,这里列出几个比较重要的属性
    producer:
      batch-size: 128
      retries: 3
      buffer-memory: 40960
      acks: all
      properties:
        linger.ms: 10

关于以上参数含义,将在下述进行讲解。

注意:spring.kafka.bootstrap-servers后面的值需要换成自己本机启动的server IP.

(2)Producer初始化

import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.StringSerializer;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Properties;


@Slf4j(topic = "kafka")
@Component
public class KafkaSender implements InitializingBean {
   

    /**
     * Kafka server服务器地址
     */
    @Value("${kafka.producer.servers}")
    private String kafkaServers;

    /**
     * Producer发送消息失败的时候重试次数
     */
    @Value("${kafka.producer.retries}")
    private int retries;

    /**
     * batch.size是producer批量发送的基本单位,
     * 默认是16384Bytes,即16kB
     */
    @Value("${kafka.producer.batch.size}")
    private int batchSize;

    /**
     * lingger.ms是sender线程在检查batch是否ready时候,
     * 判断有没有过期的参数,默认大小是0ms
     */
    @Value("${kafka.producer.linger}")
    private int linger;

    /**
     * producer可以用来缓存数据的内存大小
     */
    @Value("${kafka.producer.buffer.memory}")
    private int bufferMemory;

    /**
     * 多少ISR副本写入成功才算消息发送成功, all代表全部
     */
    @Value("${kafka.producer.acks}")
    private String acks;

    private KafkaProducer<String, String> producer;

		/**
		 * 初始化
		 */
    @Override
    public void afterPropertiesSet() throws Exception {
   
        Properties props = new Properties();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaServers);
        props.put(ProducerConfig.RETRIES_CONFIG, retries);
        props.put(ProducerConfig.BATCH_SIZE_CONFIG, batchSize);
        props.put(ProducerConfig.LINGER_MS_CONFIG, linger);
        props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, bufferMemory);
        props.put(ProducerConfig.ACKS_CONFIG, acks);
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);

        producer = new KafkaProducer<>(props);
    }
}

(3)消息发送

生产者在启动的时候,首先与我们指定的Broker建立一个TCP连接,之后向Kafka Broker发送消息。

目前,新版本的Kafka Producer的消息发送都是异步的,这代表你调用Kafka Producer的消息发送API会立即返回,但是不表示消息一定发送成功。

Kafka Producer消息发送API一般有两种:

// 无回调
producer.send(msg);
// 有回调  
producer.send(msg, callback)

这两个有啥区别呢?

producer.send(msg)是无回调的,即调用者调用该API后会立即返回,无论是否发送成功。假如发送过后因为网络抖动导致消息没有发送至Kafka Broker端,调用者是无法感知该消息是否发送成功的,所以可能导致消息丢失;

producer.send(msg, callback):带回调的消息发送,即调用者调用该API后,消息如果成功发送至Broker端会在回调中告知消息成功发送。所以我们可以在回调里做一些处理,如果回调内容为空或者返回异常,那么就代表此条消息没有发送成功,我们可以通过重试来重新发送。该API可以避免Producer端消息丢失(当然,还需要Broker端的一些参数配置)。不过,由于带有回调,所以性能要比不带回调的API性能低一点。

下面想敲个黑板,简单说下生产环境如何正确实现Kafka producer消息发送。

(1)在生产环境中,我们优先推荐使用带有回调的API:producer.send(msg, callback)

(2)设置 acks = all,acks 是 Producer 的一个参数,如果设置为all代表所有副本Broker接收并写入消息,这条消息才算是发送成功。如果不设置为all,假设第一台接收到消息并返回Producer消息成功后立马宕机,那么这条消息可能就算是丢失。

你可能感兴趣的:(Java进阶,消息队列,SpringBoot,Kafka,kafka生产者代码实现,Kafka消费者代码实现)