赞
踩
一、什么是 Kafka ?
二、为什么要用 Kafka ?
三、Kafka 环境安装
四、Spring Boot 2.x 整合 Kafka
五、总结
六、GitHub 源码地址
Kafka 是 Apache 基金会开源的一个分布式发布 - 订阅消息中间件,流处理平台。 它起源于 LinkedIn,由 Scala 和 Java两种语言编写而成。于 2011 年成为 Apache 项目,2012 成为 Apache 基金会下顶级项目。
Kafka 专为分布式高吞吐系统而设计。相比较其他消息中间件,如 RabbitMq 等,Kafka 具有更好的吞吐量,内置分区,复制和固有的容错能力,使得它非常适合应用在大数据领域。另外,Kafka 还支持离线、在线消费消息。
接下来,小哈为大家演示一下,在 Linux 系统中,采用最简单的单机安装方式, 因为本文着重点还是介绍 Spring Boot 2.x 快速集成整合 Kafka.
访问 Kafka 官网 http://kafka.apache.org/downloads,下载 tgz 包, 这里演示版本为最新的 2.3.0 版本。
下载下来过后,放置到指定位置,执行命令解压:
tar -zxvf kafka_2.11-2.3.0.tgz
解压完成后,进入 Kafka 目录下:
cd kafka_2.11-2.3.0
通过 bin 目录下的 zookeeper-server-start.sh
启动脚本,来启动 zk 单节点实例:
bin/zookeeper-server-start.sh -daemon config/zookeeper.properties
通过 bin 目录下的 kafka-server-start.sh
来启动 :
bin/kafka-server-start.sh config/server.properties
注意:Kafka 默认使用 9092 端口,注意关闭防火墙,阿里云服务器的话,记得添加安全组。
新建一个 Spring Boot 2.x Web 工程。
小哈这里完整的 maven 依赖如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.1.2.RELEASE</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <groupId>site.exception</groupId>
- <artifactId>spring-boot-kafka</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>spring-boot-kafka</name>
- <description>Demo project for Spring Boot</description>
-
- <properties>
- <java.version>1.8</java.version>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <!-- Kafka -->
- <dependency>
- <groupId>org.springframework.kafka</groupId>
- <artifactId>spring-kafka</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.kafka</groupId>
- <artifactId>spring-kafka-test</artifactId>
- <scope>test</scope>
- </dependency>
-
- <!-- lombok -->
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <optional>true</optional>
- </dependency>
-
- <!-- 阿里巴巴 fastjson -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>1.2.58</version>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- <scope>runtime</scope>
- <optional>true</optional>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
-
- </project>

修改 application.yml 文件,添加 kafka 相关配置:
- spring:
- kafka:
- # 指定 kafka 地址,我这里在本地,直接就 localhost, 若外网地址,注意修改【PS: 可以指定多个】
- bootstrap-servers: localhost:9092
- consumer:
- # 指定 group_id
- group-id: group_id
- auto-offset-reset: earliest
- # 指定消息key和消息体的编解码方式
- key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
- value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
- producer:
- # 指定消息key和消息体的编解码方式
- key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
- value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
auto.offset.reset
配置有3个值可以设置,分别如下:
offset
时,从提交的 offset
开始消费;无提交的 offset
时,从头开始消费;offset
时,从提交的 offset
开始消费;无提交的 offset
时,消费新产生的该分区下的数据;topic
各分区都存在已提交的 offset
时,从 offset
后开始消费;只要有一个分区不存在已提交的 offset
,则抛出异常;默认建议用 earliest
, 设置该参数后 kafka出错后重启,找到未消费的offset可以继续消费。
而 latest 这个设置容易丢失消息,假如 kafka 出现问题,还有数据往topic中写,这个时候重启kafka,这个设置会从最新的offset开始消费, 中间出问题的哪些就不管了。
none 这个设置没有用过,兼容性太差,经常出问题。
模拟业务系统中,用户每下一笔订单,就发送一个消息,供其他服务消费:
- /**
- * @author 犬小哈(公众号:小哈学Java)
- * @date 2019/4/12
- * @time 下午3:05
- * @discription 订单实体类
- **/
- @Data
- @Builder
- @AllArgsConstructor
- @NoArgsConstructor
- public class Order {
- /**
- * 订单id
- */
- private long orderId;
- /**
- * 订单号
- */
- private String orderNum;
- /**
- * 订单创建时间
- */
- private LocalDateTime createTime;
- }

新建一个 KafkaProvider
消息提供者类,源码如下:
- /**
- * @author 犬小哈(公众号:小哈学Java)
- * @date 2019/4/12
- * @time 下午3:05
- * @discription 消息提供者
- **/
- @Component
- @Slf4j
- public class KafkaProvider {
-
- /**
- * 消息 TOPIC
- */
- private static final String TOPIC = "xiaoha";
-
- @Autowired
- private KafkaTemplate<String, String> kafkaTemplate;
-
- public void sendMessage(long orderId, String orderNum, LocalDateTime createTime) {
- // 构建一个订单类
- Order order = Order.builder()
- .orderId(orderId)
- .orderNum(orderNum)
- .createTime(createTime)
- .build();
-
- // 发送消息,订单类的 json 作为消息体
- ListenableFuture<SendResult<String, String>> future =
- kafkaTemplate.send(TOPIC, JSONObject.toJSONString(order));
-
- // 监听回调
- future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {
- @Override
- public void onFailure(Throwable throwable) {
- log.info("## Send message fail ...");
- }
-
- @Override
- public void onSuccess(SendResult<String, String> result) {
- log.info("## Send message success ...");
- }
- });
- }
- }

消息发送出去了,当然就需要一个消费者,消费者拿到消息后,再做相关的业务处理,这里,小哈仅仅是打印消息体。
添加 KafkaConsumer
消费者类:
- /**
- * @author 犬小哈(公众号:小哈学Java)
- * @date 2019/4/12
- * @time 下午3:05
- * @discription 消息消费者
- **/
- @Component
- @Slf4j
- public class KafkaConsumer {
-
- @KafkaListener(topics = "xiaoha", groupId = "group_id")
- public void consume(String message) {
- log.info("## consume message: {}", message);
- }
- }
通过 @KafkaListener
注解,我们可以指定需要监听的 topic
以及 groupId
, 注意,这里的 topics
是个数组,意味着我们可以指定多个 topic
,如:@KafkaListener(topics = {"xiaoha", "xiaoha2"}, groupId = "group_id")
。
注意:消息发布者的 TOPIC 需要保持与消费者监听的 TOPIC 一致,否者消费不到消息。
新建单元测试,功能测试消息发布,以及消费。
- /**
- * @author 犬小哈(公众号:小哈学Java)
- * @date 2019/4/12
- * @time 下午3:05
- * @discription
- **/
- @RunWith(SpringRunner.class)
- @SpringBootTest
- public class SpringBootKafkaApplicationTests {
-
- @Autowired
- private KafkaProvider kafkaProvider;
-
- @Test
- public void sendMessage() throws InterruptedException {
- // 发送 1000 个消息
- for (int i = 0; i < 1000; i++) {
- long orderId = i+1;
- String orderNum = UUID.randomUUID().toString();
- kafkaProvider.sendMessage(orderId, orderNum, LocalDateTime.now());
- }
-
- TimeUnit.MINUTES.sleep(1);
- }
- }

发送 1000 个消息,看消息是否能够被正常发布与消费,控制台日志如下:
可以发现,1000 个消息被成功发送,且被正常消费。
我们再验证下 Kafka 的 topic 列表,看 xiaoha
这个topic
是否正常被创建, 执行 bin
目录下查看 topic
列表的 kafka-topics.sh
脚本:
bin/kafka-topics.sh --list --zookeeper localhost:2181
好了,大功告成!
小哈今天主要和大家分享了,如何安装单机版的 kafka 环境、如何在 Spring Boot 2.x 中快速集成消息中间件 Kafka,以及演示了相关示例代码来发布消息、消费消息,希望大家看完过后有所收获,下期见!
https://github.com/weiwosuoai/spring-boot-tutorial/tree/master/spring-boot-kafka
欢迎关注公众号: 小哈学Java (ID: xiaoha_java), 专注于分享Java领域干货文章, 不限于 BAT 面试题分享,Spring Boot, Spring Cloud, 高并发,JVM, 数据库,Docker 容器, ELK 等相关知识,另外,关注即可 免费无套路领取 100G 学习面试资料哟~
https://zh.wikipedia.org/wiki/Kafka
https://www.w3cschool.cn/apache_kafka/
https://juejin.im/post/5d406a925188255d352ab24e
https://www.jianshu.com/p/e1df7d18bb8f
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。