SpringBoot整合Kafka使用

184 阅读3分钟

** 2019-11-21 16:04:11 **

终于想起了我有博客...最近好不容易忙完巡检模块,想写点什么。

之前公司订餐系列模块用到了kafka,整理一些配置和使用把。

一.整理的一些bootstrap.yml配置

都是网上啊啥找的一些配置信息,可以参考使用。 具体的优化啊,高级配置的话还是参照官网kafka去琢磨加深把。

  kafka:
    bootstrap-servers: 192.168.1.1 #你kafka服务器地址
    #生产者的配置,大部分我们可以使用默认的,这里列出几个比较重要的属性
    producer:
      #每批次发送消息的数量
      batch-size: 16
      #设置大于0的值将使客户端重新发送任何数据,一旦这些数据发送失败。
      #注意,这些重试与客户端接收到发送错误时的重试没有什么不同。允许重试将潜在的改变数据的顺序,
      #如果这两个消息记录都是发送到同一个partition,则第一个消息失败第二个发送成功,则第二条消息会比第一条消息出现要早。
      retries: 0
      #producer可以用来缓存数据的内存大小。如果数据产生速度大于向broker发送的速度,
      #producer会阻塞或者抛出异常,以“block.on.buffer.full”来表明。
      #这项设置将和producer能够使用的总内存相关,但并不是一个硬性的限制,
      #因为不是producer使用的所有内存都是用于缓存。一些额外的内存会用于压缩(如果引入压缩机制),同样还有一些用于维护请求。
      buffer-memory: 33554432
      acks: all
      #key序列化方式
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
    #消费者的配置
    consumer:
      #Kafka中没有初始偏移或如果当前偏移在服务器上不再存在时,默认区最新 ,有三个选项 【latest, earliest, none】
      auto-offset-reset: latest
      #是否开启自动提交
      enable-auto-commit: false
      #自动提交的时间间隔
      auto-commit-interval: 100
      #key的解码方式
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      #value的解码方式
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      #在/usr/local/etc/kafka/consumer.properties中有配置
      group-id: consumerGroup #【你自己配置的】

二.Kafka生产者


import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.ProducerListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;


/**
 * 生产者
 *
 * @author aman
 * @date 2019/10/26
 */
@Slf4j
@Component
@AllArgsConstructor
public class OrderSendMsgByKafka {

    private KafkaTemplate<String, String> kafkaTemplate;
    private final RepastOrderService repastOrderService;
    private static final String TOPIC_NAME = "CloudSchoolRepast";

    /**
     * 定时任务每天一点发送每天的订餐信息
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void sendOrderMessageByKafka() {
        /**
         * 发送数据到消息队列
         * send有多个重载方法
         */
        try {
            kafkaTemplate.send(TOPIC_NAME, 0, "data", JSON.toJSONString(order));
        } catch (Exception e) {
            log.error("发送异常try : 主题名称topic = {}, 异常exception = {}", TOPIC_NAME);
        }
        //消息发送的监听器,用于回调返回信息
        kafkaTemplate.setProducerListener(new ProducerListener<String, String>() {
            /**
             * 成功后调用
             * @param topic 主题
             * @param partition 目标分区
             * @param key 键
             * @param value 值
             * @param recordMetadata 发送成功的结果
             */
            @Override
            public void onSuccess(String topic, Integer partition, String key, String value, RecordMetadata recordMetadata) {
                log.info("发送成功 : 主题名称topic = {}, 分区partition = {}, 键key = {}, 值value = {}, recordMetadata = {}", topic, partition, key, value, recordMetadata);
            }
            /**
             * 失败后调用, ProducerRecord被覆盖后不调用
             * @param topic 主题
             * @param partition 目标分区
             * @param key 键
             * @param value 值
             * @param exception 异常
             */
            @Override
            public void onError(String topic, Integer partition, String key, String value, Exception exception) {
                log.error("发送异常onError : 主题名称topic = {}, 分区partition = {}, 键key = {}, 值value = {}, 异常exception = {}", topic, partition, key, value, exception);
            }
        });
    }
    
}

三.Kafka消费者


import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.annotation.TopicPartition;
import org.springframework.stereotype.Component;

import java.util.Optional;

/**
 * Kafka消费者
 *
 * @author caoxiang
 * @date 20119/10/26
 */
@Component
@Slf4j
@AllArgsConstructor
public class RepastConsumer {

    private static final String TOPIC_NAME = "CloudSchoolRepast";
    private final RepastOrderService repastOrderService;

    @KafkaListener(id = "RepastConsumerAfter", topicPartitions = {@TopicPartition(topic = TOPIC_NAME, partitions = {"1"})})
    public void listen(ConsumerRecord<?, ?> record) {
        /**
         *  如果record.value()为空,返回空的Optional,
         *  否则返回一个value值为record.value()的Optional
         */
        Optional<?> kafkaMessage = Optional.ofNullable(record.value());
        log.info("Receiver record = {}", record);
        /**
         * 判断Optional的value值是否为空
         */
        if (kafkaMessage.isPresent()) {
            /**
             * 获取Optional的value值  List<OrderBySendKafka>
             */
            Object message = kafkaMessage.get();
            log.info("Receiver message = {}", message);
        }
    }
    
}