Kafka 是一个开源的分布式流处理平台,最初由 LinkedIn 开发并贡献给 Apache 软件基金会。它设计用于构建高性能、持久性、可伸缩和容错的实时数据管道和流处理应用程序。
以下是 Kafka 的一些关键特点和概念:
Kafka 提供了高性能、可靠、持久的消息传递系统,适用于大规模的实时数据处理和流式处理应用程序。它已经成为许多企业构建实时数据管道和流处理应用程序的首选工具之一。
Kafka 的运行原理涉及多个组件和过程,主要包括生产者发送消息、消息存储在代理 (Broker) 中的分区中、消费者从分区中读取消息等。以下是 Kafka 的基本运行原理:
通过这些组件和过程,Kafka 实现了高吞吐量、持久性、分布式和水平扩展等特性,使得它成为处理大规模实时数据流的理想选择。
首先,在你的 Spring Boot 项目的 pom.xml
文件中添加 Spring Kafka 的依赖:
<dependency>
<groupId>org.springframework.kafkagroupId>
<artifactId>spring-kafkaartifactId>
dependency>
在 application.properties
或 application.yml
中添加 Kafka 服务器的连接信息:
kafka:
bootstrap-servers: 192.168.193.131:9092
producer: #生产者序列化器
retries: 10 #如果发生故障,生产者将尝试重新发送消息的次数。
key-serializer: org.apache.kafka.common.serialization.StringSerializer #序列化生产者消息键的类。
value-serializer: org.apache.kafka.common.serialization.StringSerializer #序列化生产者消息值的类。
ack-mode: manual
consumer: #消费者序列化器
group-id: ${spring.application.name}-test # 消费者组的唯一标识符。在消费者组中的所有消费者将共享消费者组的工作负载。
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer #用于反序列化消费者消息键的类。
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer #用于反序列化消费者消息值的类。
listener: #配置了监听器相关的设置。
ack-mode: manual #开启手动确认 设置为手动,表示消费者将等待手动确认来确定是否已成功处理消息。
配置 Kafka 主题(topic)的创建
@Configuration
public class KafkaConfig {
/**
* @return org.apache.kafka.clients.admin.NewTopic
* @date 2024/5/31 14:42
* @Description: TODO @Bean 注解
* 作用:将方法返回的对象注册为 Spring 容器中的一个 Bean。
* 返回值类型:NewTopic,表示 Kafka 主题的配置信息。
*/
@Bean
public NewTopic viewUserTopic(){
/*第一个参数:主题名称,这里是 "viewUserTopic"。
第二个参数:分区数量,这里设置为 1。
第三个参数:副本数量,这里设置为 1。*/
return new NewTopic("viewUserTopic",1,(short) 1);
}
}
@Autowired
private KafkaTemplate kafkaTemplate;
//定义消息的唯一ID 防止消息重复消费
String msgId = "msg-" + UUID.randomUUID().toString();
//定义消息内容
String msgBody = JSON.toJSONString(tbUser);
//将消息唯一表示存入redis缓存 防止消息重复消费
stringRedisTemplate.opsForValue().set(msgId, msgBody);
/*组装消息体 发送消息队列*/
MessageVO messageVO = new MessageVO();
messageVO.setMsgID(msgId);
messageVO.setMsgBody(msgBody);
//向名为 "viewUserTopic" 的 Kafka 主题发送消息。
//参数一: 表示目标 Kafka 主题的名称。 参数二:消息内容
kafkaTemplate.send("viewUserTopic", JSON.toJSONString(messageVo))
//通过该方法设置回调函数,用于处理消息发送的成功和失败情况。
.addCallback(
//成功回调函数,处理消息发送成功的情况。
new SuccessCallback() {
@Override
public void onSuccess(Object o) {
// 消息发送成功
System.out.println("kafka 消息发送成功了~~~~~~~~~~~~");
}
},
//失败回调函数,处理消息发送失败的情况。
new FailureCallback() {
@Override
public void onFailure(Throwable throwable) {
// 消息发送失败了,再次发送
System.out.println("kafka 消息发送失败了,再次发送");
kafkaTemplate.send("viewUserTopic", JSON.toJSONString(messageVo));
}
}
);
/**
* @param message 表示接收到的消息内容,这里是 JSON 格式的字符串。
* @param acknowledgment 用于手动提交消费者偏移量的对象。
* @date 2024/5/31 15:13
* @Description: TODO
* @KafkaListener 通过该注解指定了监听的 Kafka 主题为 "viewUserTopic"。
*/
@KafkaListener(topics = "viewUserTopic")
public void recvViewUserMessage(String message, Acknowledgment acknowledgment) {
//--1 接收消息
MessageVO messageVo = JSON.parseObject(message, MessageVO.class);
//--2 根据消息的唯一ID,判断消息是否重复
String msgId = messageVo.getMsgID();
if (!stringRedisTemplate.hasKey(msgId)) {
// 消息重复了
System.out.println("kafka 消息重复了");
// 使用 acknowledgment.acknowledge() 方法手动确认消费完成,通知 Kafka 服务器该消息已经被处理。
acknowledgment.acknowledge();
return;
}
//--3 消费消息(处理消息)
String msgBody = messageVo.getMsgBody();
TbLog tbLog = JSON.parseObject(msgBody, TbLog.class);
tbLog.setCreateTime(new Date());
tbLogMapper.insert(tbLog);
//--4 手动确认消息
//手动确认消费完成,通知 Kafka 服务器该消息已经被处理。
acknowledgment.acknowledge();
//--5 删除消息的唯一ID,防止消息重复消费
stringRedisTemplate.delete(msgId);
}