学习日记--SpringBoot整合kafka(zookeeper)--服务器配置--后端实现
1.创建zookeeper容器(直接创建容器时如果没有镜像会自动拉取最新版本的镜像)
docker run -d --name zookeeper -p 2181:2181 -v /etc/localtime:/etc/localtime wurstmeister/zookeeper
2.创建kafka容器
## KAFKA_ZOOKEEPER_CONNECT 需要修改成zookeeper所在容器IP,容器之间是可以通过IP访问的 docker run -d --name kafka -p 9092:9092 -e KAFKA_BROKER_ID=1 -e KAFKA_ZOOKEEPER_CONNECT=172.17.0.9:2181 -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://47.100.215.27:9092 -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 -v /etc/localtime:/etc/localtime -t wurstmeister/kafka:latest
参数
-e KAFKA_BROKER_ID=0 //在kafka集群中,每个kafka都有一个BROKER_ID来区分自己 -e KAFKA_ZOOKEEPER_CONNECT=172.17.0.9:2181//kafka 配置zookeeper管理kafka的路径 //zookeeper地址 -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://47.100.215.27:9092 //把kafka的地址端口注册给zookeeper -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 //配置kafka的监听端口 -v /etc/localtime:/etc/localtime //容器时间同步虚拟机的时间
zookeeper容器的ip地址使用docker inspect [容器id] 查看如下图
tips:创建过程中遇到的问题时记得用docker logs查看容器日志,如果free -h查看的内存不足可以通过增加swap空间解决
三种创建方式
·作用于内网
## KAFKA_ZOOKEEPER_CONNECT 需要修改成zookeeper所在容器IP(docker inspect查看),容器之间是可以通过IP访问的,但是不能填写成虚拟IP docker run -d --name kafka -p 9092:9092 -e KAFKA_BROKER_ID=1 -e KAFKA_ZOOKEEPER_CONNECT=172.17.0.9:2181 -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 -v /etc/localtime:/etc/localtime -t wurstmeister/kafka:latest
·作用于外网(一般不存在)
docker run -d --name kafka -p 9092:9092 -e KAFKA_BROKER_ID=1 -e KAFKA_ZOOKEEPER_CONNECT=(服务器外网IP):2181 -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://(服务器外网IP):9092 -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 -v /etc/localtime:/etc/localtime -t wurstmeister/kafka:latest # 2.然后再本机的hosts文件中中添加 服务器的外网ip和对应的服务器名字,例如:(服务器外网IP) VM-24-5-centos # 3.java代码中直接使用代码: # // 设置配置文件的方式 Properties properties = new Properties(); # // 设置链接的主服务器 # // 连接当前远程的服务器出现了url错误,需要进行修改,切记加上9092 properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "VM-24-5-centos:9092");
·整合SpringBoot
docker run -d --name kafka -p 9092:9092 -e KAFKA_BROKER_ID=0 -e KAFKA_ZOOKEEPER_CONNECT=(服务器内网IP):2181 -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://(服务器外网IP):9092 -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 -t wurstmeister/kafka:latest
内网ip和外网ip可以去自己的云服务器看
3.创建好后可以进入容器测试kafka
4.后端代码
yml配置
kafka: bootstrap-servers: kafka服务器ip:端口 producer: # producer 生产者 retries: 0 # 重试次数 acks: 1 # 应答级别:多少个分区副本备份完成时向生产者发送ack确认(可选0、1、all/-1) batch-size: 16384 # 批量大小 buffer-memory: 33554432 # 生产端缓冲区大小 key-serializer: org.apache.kafka.common.serialization.StringSerializer # value-serializer: com.itheima.demo.config.MySerializer value-serializer: org.apache.kafka.common.serialization.StringSerializer consumer: # consumer消费者 group-id: defaultConsumerGroup # 默认的消费组ID enable-auto-commit: true # 是否自动提交offset auto-commit-interval-ms: 1000 # 提交offset延时(接收到消息后多久提交offset) # earliest:当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费 # latest:当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据 # none:topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常 auto-offset-reset: latest key-deserializer: org.apache.kafka.common.serialization.StringDeserializer # value-deserializer: com.itheima.demo.config.MyDeserializer value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
生产者(一般是在控制层或者业务层调用)
package com.example.demo.component; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.support.SendResult; import org.springframework.stereotype.Component; import org.springframework.util.concurrent.ListenableFuture; import org.springframework.util.concurrent.ListenableFutureCallback; /** * @Date 2022/7/7 15:07 * @ClassName kafkaProducer * @Description ToDo * @Author LongX **/ @Component public class KafkaProducer { /** * KafkaTemplate泛型类型跟消费者ConsumerRecord的泛型类型保持一致 */ @Autowired private KafkaTemplate<String,String> kafkaTemplate; /** * 发送消息 */ public void sendMessage() { try{ //生产消息 String message = "hello ! 测试kafka "; ListenableFuture<SendResult<String, String>> listenableFuture = kafkaTemplate.send("hello","hello", message); listenableFuture.addCallback(new ListenableFutureCallback<SendResult<String, String>>() { @Override public void onSuccess(SendResult<String, String> result) { System.out.println("sendMessage success"); } @Override public void onFailure(Throwable ex) { System.out.println("sendMessage error"); } }); }catch (Exception e){ System.out.println("sendMessage exception"); } } }
消费者(监听某些topic就可以了)
package com.example.demo.component; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.stereotype.Component; /** * @Date 2022/7/7 15:36 * @ClassName TopicComponent * @Description ToDo * @Author LongX **/ @Component public class TopicComponent { @KafkaListener(topics = {"hello","hello2"}) public void handMessage(ConsumerRecord<String, String> record){ String topic = record.topic(); String msg = record.value(); System.out.println("消费者接受消息:topic-->"+topic+",msg->>"+msg); } }
生产调用实例(控制层)
package com.example.demo.controller; import com.example.demo.component.KafkaProducer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @Date 2022/7/7 15:30 * @ClassName KafkaProController * @Description ToDo * @Author LongX **/ @RestController public class KafkaProController { @Autowired private KafkaProducer kafkaProducer; @RequestMapping("/hello") public String hello(){ System.out.println("------->测试生产者发送消息"); kafkaProducer.sendMessage(); return "kafka消息已发送."; } }