怎么使用Kafka?收藏这篇短文就可以了

〇、前言

便于大家对本章内容的理解,我重新整理了一下Kafka中的部分重要概念,以表格的方式呈现出来,请见下表所示:

名词 解释
Broker 节点 一个Kafka节点就是一个Broker,一个和多个Broker可以组成一个Kafka集群
Topic 主题 Kafka根据topic对消息进行归类,发布到kafka集群的每套消息都需要指定一个topic,topic是一个逻辑概念,物理上是不存在的
Producer 生产者 用于向Kafka中发送消息
Consumer 消费者 从Kafka中获取消息
Consumer Group 消费组 每个Consumer都会归属于一个消费组,一条消息可以同时被多个不同的消费组消费,但是只能被一个消费组中的消费者消费
Partition 分片 物理上的概念,可以将一个topic上的数据拆分为多分放到Partition中,每个Patition内部的消息是有序的。

本篇文章的主要目的就是操作一下Kafka,从直观感受上面使用一下它,而不是让它仅仅存在于我们理论和想象中的认知上。

那么对于这种中间件的操作,我们一般来说普遍会采用两种方式:

方式1 】通过bin路径下的脚本指令,在控制台端进行使用操作;

方式2】通过对jar包的引用,在代码层面上进行使用操作;

在下面章节中,我们就分别针对控制台层面操作代码层面操作这两个方面,对Kafka进行第一次亲密的接触。

一、控制台层面操作

对于Kafka支持多少控制台指令,在其官网(https://kafka.apache.org/documentation/#quickstart)中就已经详细的列举出来了,我们可以很方面的从官网中获得对某个指令的解释和使用说明,如下所示:

同样,在我们的安装了Kafka的bin目录下,也存在着对应这些指令的sh脚本文件, 也是它构成了我们可以非常方便的在控制台这一层面操作Kafka的可能性,如下所示:

虽然指令和脚本文件挺多的,但是我们没有必要从头学一遍,毕竟是第一次操作Kafka,我们只做3件事:创建Topic、通过Producer发送消息和通过Consumer接受消息。

1.1> 创建/查看主题(kafka-topics.sh

当我们发送消息的时候,主题topic是我们重要的参数之一,我们可以针对不同业务创建不同的topic,从而达到对消息的隔离性 。在bin目录下,负责管理Topic的脚本是kafka-topics.sh,我们可以通过对它操作来实现topic的管理。下面,我们就来尝试创建一个名称为"muse"的Topic。

java 复制代码
kafka_2.13-3.0.0> bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic muse --partitions 1 --replication-factor 1

Created topic muse.

--bootstrap-server 】待链接到的Kafka服务地址,此处我们指定localhost:9092

--create 】执行创建Topic主题指令;

--topic 】指定待创建的主题名称,此处我们指定创建名称为"muse"的topic;

--partitions 】指定分区个数,由于我们采用单机模式,即只有1个Broker,所以指定创建1个分区

--replication-factor 】指定创建副本的个数,此处我们指定创建1个副本,即主副本;

创建完主题Topic之后,我们也可以通过 --list指令 查看Kafka下所有主题列表,如下所示:

java 复制代码
kafka_2.13-3.0.0> bin/kafka-topics.sh --list --bootstrap-server localhost:9092                

muse

同样的,我们也可以通过 --describe指令 查看刚刚创建的那个名称为"muse"的Topic内的具体描述信息:

java 复制代码
kafka_2.13-3.0.0> bin/kafka-topics.sh --describe --topic muse --bootstrap-server localhost:9092                            
Topic: muse	TopicId: iDQpnERjSI2IvaB2kaB2aQ	PartitionCount: 1	ReplicationFactor: 1	Configs: segment.bytes=1073741824
Topic: muse	Partition: 0	Leader: 0	Replicas: 0	Isr: 0

1.2> 生产端(kafka-console-producer.sh

在上面,我们已经创建好了名称为"muse"的主题Topic了,那么我们就可以尝试向这个Topic发送消息了。此时,我们可以通过使用kafka-console-producer.sh来发送消息,它可以从本地文件中读取内容,或者我们也可以从命令行中直接输入内容,并将这些内容以消息的形式发送到kafka集群中。在默认情况下,每一行都会被当做一个独立的消息。具体发送语句如下所示:

java 复制代码
kafka_2.13-3.0.0> bin/kafka-console-producer.sh --topic muse --bootstrap-server localhost:9092                
>message1
>message2
>

其中,通过使用--bootstrap-server来指定Kafka服务地址;如果配置了Kafka集群,用逗号分割即可。

1.3> 消费端(kafka-console-consumer.sh

上面我们虽然向Kafka中发送了两条消息------message1message2,但是由于此时并没有任何消费者Consumer,所以这两个消息也无法被读取。那么,我们可以利用kafka-console-consumer.sh来执行消息消费操作,具体消费指令如下所示:

java 复制代码
kafka_2.13-3.0.0> bin/kafka-console-consumer.sh --topic muse --bootstrap-server localhost:9092                

我们发现执行了上面的指令,控制台没有输入任何内容 ,那么,我们切换到Producer段,再发送两条消息------message3message4,我们发现,此时Consumer端有消息输出了,如下所示:

java 复制代码
kafka_2.13-3.0.0> bin/kafka-console-consumer.sh --topic muse --bootstrap-server localhost:9092                

message3
message4

发生上面情况的原因就是,在默认情况下,消费者是从最后一条消息的偏移量+1开始消费,即:Consumer客户端启动之前的消息是不会被消费的 。那如果我们想要把Consumer客户端启动之前的消息也获取到,则可以添加--from-beginning参数即可,如下所示:

java 复制代码
kafka_2.13-3.0.0> bin/kafka-console-consumer.sh --topic muse --bootstrap-server localhost:9092 --from-beginning

message1
message2
message3
message4

二、代码层面操作

项目中引入kafka-clients的依赖(也可以直接引入spring-kafka的依赖,里面内嵌了kafka-clients)

2.1> 编写生产者端

2.1.1> 初始化配置

创建配置对象Properties

Properties properties = new Properties();

配置kafka的Broker列表

properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "127.0.0.1:9093,127.0.0.1:9094,127.0.0.1:9095");

发出消息持久化机制参数

properties.put(ProducerConfig.ACKS_CONFIG, "1");

ACKS_CONFIG的类型有如下3种:

【acks=0】表示producer不需要等待 任何broker确认收到消息的ACK回复,就可以继续发送下一条消息。性能最高,但是最容易丢失消息。
【acks=1】表示至少等待leader已经成功 将数据写入本地log,但是不需要等待所有follower都写入成功,就可以继续发送下一条消息。这种情况下,如果follower没有成功备份数据,而此时leader又挂掉,则消息就会丢失。
【acks=-1/all】需要等待所有min.insync.replicas(默认为1,推荐配置>=2)这个参数配置的副本个数都成功写入日志。这种策略会保证只要有一个备份存活就不会丢失数据。这是最强的数据保证。

配置失败重试机制

properties.put(ProducerConfig.RETRIES_CONFIG, 3); // 失败重试3次

properties.put(ProducerConfig.RETRY_BACKOFF_MS_CONFIG, 300); // 重试间隔300ms

配置缓存相关信息

Producer的消息会先发送到本地缓冲区 (BUFFER_MEMORY_CONFIG),而不是发送一次消息连接一次kafka。

kafka本地线程会从缓冲区去取数据 (BATCH_SIZE_CONFIG),然后批量发送到Broker ,即:一个批次满足16KB 就会发送出去。

LINGER_MS_CONFIG的默认值为0,表示消息必须立即被发送,但这样会影响性能。 设置10ms也就是说Producer消息发送完后会进入本地的batch中;如果10ms内,这个batch满足了16KB,那么就会随着batch一起被发送出去。如果10ms内,batch没满,那么也必须要把消息发送出去,不能让消息的发送延迟时间太长。

配置key和value的序列化实现类

java 复制代码
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());

2.1.2> 同步消息发送

同步消息发送代码如下所示

2.1.3> 异步消息发送

2.2> 编写消费者端

2.2.1> 初始化配置

创建配置对象Properties

Properties properties = new Properties();

配置kafka的Broker列表

properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "127.0.0.1:9093,127.0.0.1:9094,127.0.0.1:9095");

配置消费组

properties.put(ConsumerConfig.GROUP_ID_CONFIG, "museGroup");

offset的重置策略

properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");

【解释】offset的重置策略------例如:创建一个新的消费组,offset是不存在的,如何对offset赋值消费。
latest :默认值,只消费自己启动之后发送到主题的消息。
earliest:第一次从头开始消费,以后按照消费offset记录继续消费。

心跳相关配置

java 复制代码
/** Consumer给Broker发送心跳的时间间隔 */
properties.put(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG, 1000);

/** 如果超过10秒没有接收到消费者的心跳,则会把消费者踢出消费组,然后重新进行rebalance操作,把分区分配给其他消费者 */
properties.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, 10*1000);

poll相关配置

java 复制代码
/** 一次poll最大拉取消息的条数,可以根据消费速度的快慢来设置 */
properties.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 500);

/** 如果两次poll的时间超出了30秒的时间间隔,kafka会认为整个Consumer的消费能力太弱,会将它踢出消费组。将分区分配给其他消费者 */
properties.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, 30*1000);

配置key和value的反序列化实现类

java 复制代码
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());

2.2.2> 自动提交offset

自动提交offset

当消费者向Broker的log中poll到消息后,默认情况下,会向broker中名称为"__consumer_offsets"的Topic发送offset偏移量。
自动提交会出现丢失消息的情况

因为如果Consumer还没消费完poll下来的消息就自动提交了偏移量,那么此时如果Consumer挂掉了,那么下一个消费者会从已经提交的offset的下一个位置开始消费消息。那么之前没有被消费的消息就丢失了。

2.2.3> 手动提交offset

手动提交offset

当消费者从kafka的Broker日志文件中poll到消息并且消费完毕之后。再手动提交当前的offset。

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享

更多技术干货,欢迎大家关注公众号"爪哇缪斯" ~ \(^o^)/ ~ 「干货分享,每天更新」

相关推荐
Piper蛋窝1 小时前
深入 Go 语言垃圾回收:从原理到内建类型 Slice、Map 的陷阱以及为何需要 strings.Builder
后端·go
prince053 小时前
Kafka 生产者和消费者高级用法
分布式·kafka·linq
六毛的毛3 小时前
Springboot开发常见注解一览
java·spring boot·后端
AntBlack3 小时前
拖了五个月 ,不当韭菜体验版算是正式发布了
前端·后端·python
31535669133 小时前
一个简单的脚本,让pdf开启夜间模式
前端·后端
uzong4 小时前
curl案例讲解
后端
菜萝卜子4 小时前
【Project】基于kafka的高可用分布式日志监控与告警系统
分布式·kafka
一只叫煤球的猫5 小时前
真实事故复盘:Redis分布式锁居然失效了?公司十年老程序员踩的坑
java·redis·后端
csdn_aspnet5 小时前
在 Windows 上安装和运行 Apache Kafka
windows·kafka
yanlele5 小时前
前端面试第 75 期 - 2025.07.06 更新前端面试问题总结(12道题)
前端·javascript·面试