Linux(Fedora)搭建 Kafka 以及 SpringBoot 开发配置
现在有使用 Kafka 的需求,所以将搭建环境的过程记录下来,希望能帮助其他人。同时附带一个 Kafka 启动脚本。
后端1分钟阅读
现在有使用 Kafka 的需求,所以将搭建环境的过程记录下来,希望能帮助其他人。同时附带一个 Kafka 启动脚本。
- JDK (_Fedora_自带,所以本文不包含)。
- Zookeeper。
- Kafka。
我安装的 ZooKeeper 3.8.1,下载地址:https://dlcdn.apache.org/zookeeper/zookeeper-3.8.1/apache-zookeeper-3.8.1-bin.tar.gz 。
解压:
tar -zxvf apache-zookeeper-3.8.1-bin.tar.gz -C /opt/module/修改配置:
mkdir -p /opt/module/zookeeper-3.8.1/zkdatas # 创建 zookeeper 数据存放目录cd /opt/module/apache-zookeeper-3.8.1-bin/conf #进入配置文件目录cp zoo_sample.cfg zoo.cfg
vi zoo.cfg # shift + g 可快速到底部
dataDir=/opt/modulezookeeper-3.8.1/zkdatas # 数据存放的目录autopurge.snapRetainCount=3 # 保留多少个快照autopurge.purgeInterval=1 # 日志多少小时清理一次server.0=127.0.0.1:2888:3888 # 配置从机
# 先使用 ?dataDir 搜索 dataDir ,可以直接改它,也可以将它删除后:wq添加myid配置:
echo 0 > /opt/module/zookeeper-3.8.1/zkdatas/myid配置防火墙:
firewall-cmd --zone=public --add-port=2181/tcp --permanent # 放开 2181 端口firewall-cmd --reload # 重载防火墙启动 Zookeeper:
cd /opt/module/apache-zookeeper-3.8.1-bin/bin/ # 进入到可执行文件目录./zkServer.sh start # 启动./zkServer.sh stauts # 查看状态
netstat -anp|grep 2181 # 查看端口是否被 zookeeper 用着jps -l # 查看是否有 zookeeper 进程如果启动失败或者没看到进程,可以在安装目录中的 logs 目录中查看日志,分析启动失败原因。
我安装的 Kafka_2.13 ,下载地址:https://downloads.apache.org/kafka/3.4.0/kafka_2.13-3.4.0.tgz 。
解压:
tar -zxvf kafka_2.13-3.4.0.tgz -C /opt/module/修改配置:
cd /opt/module/kafka_2.13-3.4.0/config/ # 进入配置文件目录cp server.properties server.properties.bak && vi server.properties # 备份配置文件后修改
?broker.id # 搜索 broker.id ,在它下面添加如下内容:
listeners=PLAINTEXT://192.168.220.128:9092
zookeeper.connect=localhost:2181 # 这是默认配置,如果需要改则改配置防火墙 :
firewall-cmd --zone=public --add-port=9092/tcp --permanentfirewall-cmd --reload启动 Kafka :
sh /opt/module/kafka_2.13-3.4.0/bin/kafka-server-start.sh -daemon /opt/module/kafka_2.13-3.4.0/config/server.properties # 根据配置文件启动
jps -l # 查看 kafka 是否已启动#!/bin/bash
# Kafka安装目录KAFKA_HOME=/opt/module/kafka_2.13-3.4.0
# 检查Kafka安装目录是否存在,若不存在则创建if [ ! -d $KAFKA_HOME ]; then sudo mkdir -p $KAFKA_HOMEfi
# 检查Java环境变量是否已经配置if [ -z "$JAVA_HOME" ]; then echo "JAVA_HOME is not set. Please set the JAVA_HOME environment variable and try again." exit 1fi
# 启动Zookeeper服务$KAFKA_HOME/bin/zookeeper-server-start.sh -daemon $KAFKA_HOME/config/zookeeper.properties
# 启动Broker服务$KAFKA_HOME/bin/kafka-server-start.sh -daemon $KAFKA_HOME/config/server.properties
# 启动监控进程while true; do # 检测Zookeeper进程是否存在 if ! pgrep -f "zookeeper"; then echo "Zookeeper process not found. Restarting..." $KAFKA_HOME/bin/zookeeper-server-start.sh -daemon $KAFKA_HOME/config/zookeeper.properties fi
# 检测Broker进程是否存在 if ! pgrep -f "kafka"; then echo "Kafka Broker process not found. Restarting..." $KAFKA_HOME/bin/kafka-server-start.sh -daemon $KAFKA_HOME/config/server.properties fi
# 每隔5秒检查一次服务状态 sleep 5done在 SpringBoot 项目中引入依赖:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.7</version></parent>
<dependencies> <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency></dependencies>application.yml 中添加如下配置:
kafka: bootstrap-servers: 192.168.220.128:9092 consumer: group-id: distribution-group producer: acks: all有两个配置类,分别配置的服务端和消费端。服务端如下:
package com.github.binarywang.demo.wx.mp.config;
import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.kafka.annotation.EnableKafka;import org.springframework.kafka.core.*;import org.springframework.kafka.support.serializer.JsonSerializer;
import java.util.HashMap;import java.util.Map;
/** * @Author kylo * @Date 2023/5/8 11:30 * @PackageName:com.github.binarywang.demo.wx.mp.config * @ClassName: KafkaConsumerConfig * @Description: TODO * @Version 1.0 */
@Configuration@EnableKafkapublic class KafkaProducerConfig {
@Value("${kafka.bootstrap-servers}") private String bootstrapServers;
// Producer Configuration @Bean public Map<String, Object> producerConfigs() { Map<String, Object> props = new HashMap<>(); props.put(org.apache.kafka.clients.producer.ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); props.put(org.apache.kafka.clients.producer.ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); props.put(org.apache.kafka.clients.producer.ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); return props; }
@Bean public ProducerFactory<String, Object> producerFactory() { return new DefaultKafkaProducerFactory<>(producerConfigs()); }
@Bean public KafkaTemplate<String, Object> kafkaTemplate() { return new KafkaTemplate<>(producerFactory()); }
}消费端配置如下:
package com.github.binarywang.demo.wx.mp.config;
import lombok.extern.slf4j.Slf4j;import org.apache.kafka.clients.consumer.ConsumerConfig;import org.apache.kafka.common.serialization.StringDeserializer;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.kafka.annotation.KafkaListener;import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;import org.springframework.kafka.config.KafkaListenerContainerFactory;import org.springframework.kafka.core.ConsumerFactory;import org.springframework.kafka.core.DefaultKafkaConsumerFactory;import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;import org.springframework.stereotype.Component;
import java.util.HashMap;import java.util.Map;
/** * @Author kylo * @Date 2023/5/8 12:35 * @PackageName:com.github.binarywang.demo.wx.mp.consumer * @ClassName: KafkaConsumer * @Description: TODO * @Version 1.0 */@Slf4j@Componentpublic class KafkaConsumerConfig {
@Value("${kafka.bootstrap-servers}") private String bootstrapServers;
@Value("${kafka.consumer.group-id}") private String groupId;
@Bean public Map<String, Object> consumerConfigs() { Map<String, Object> props = new HashMap<>(); props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); return props; }
@Bean public ConsumerFactory<String, String> consumerFactory() { return new DefaultKafkaConsumerFactory<>(consumerConfigs()); }
@Bean public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<String, String>> kafkaListenerContainerFactory() { ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>(); factory.setConsumerFactory(consumerFactory()); return factory; }
@KafkaListener(topics = "success-recommendation", groupId = "${kafka.consumer.group-id}") public void receiveMessage(Object message) { log.info("\n接 MQ 请求:requestBody=[\n{}\n] ", message); }
}消费者配置类中有一个 reveiveMessage 方法,与它对应的是谁呢?在 KafkaController 中:
package com.github.binarywang.demo.wx.mp.controller;
import com.github.binarywang.demo.wx.mp.service.KafkaService;import lombok.AllArgsConstructor;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;
/** * @Author kylo * @Date 2023/5/8 12:44 * @PackageName:com.github.binarywang.demo.wx.mp.controller * @ClassName: KafkaController * @Description: TODO * @Version 1.0 */@AllArgsConstructor@RestController@RequestMapping("/kafka")public class KafkaController {
@Autowired KafkaService kafkaService;
@GetMapping() public String sendTest(@RequestBody Object obj) { kafkaService.sendMessage("success-recommendation", obj); return "success"; }
}Service 代码如下:
package com.github.binarywang.demo.wx.mp.service;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.configurationprocessor.json.JSONObject;import org.springframework.kafka.core.KafkaTemplate;import org.springframework.stereotype.Service;
/** * @Author kylo * @Date 2023/5/8 12:18 * @PackageName:com.github.binarywang.demo.wx.mp * @ClassName: KafkaProducerService * @Description: TODO * @Version 1.0 */@Servicepublic class KafkaService {
@Autowired private KafkaTemplate<String, Object> kafkaTemplate;
public void sendMessage(String topic, Object message){ kafkaTemplate.send(topic, message); }
}至此,Kafka 环境搭建以及搭配 SprinBoot 开发的方法已记录完毕。