写在前面:我是「且听风吟」,目前是某上市游戏公司的大数据开发工程师,热爱大数据开源技术,喜欢分享自己的所学所悟,现阶段正在从头梳理大数据体系的知识,以后将会把时间重点放在Spark和Flink上面。
如果你也对大数据感兴趣,希望在这个行业一展拳脚。欢迎关注我,我们一起学习。博客地址:https://blog.csdn.net/qq_26803795
博客的名字来源于:且听风吟,静待花开。也符合我对技术的看法,想要真正掌握一门技术就需要厚积薄发的毅力,同时保持乐观的心态。
你只管努力,剩下的交给时间!
文章目录
一、前言
前些天和大家一起深入分析了kafka架构方法的知识,这部分内容偏向于理论,不过也是大数据开发工程师必须要掌握的知识点。
kafka架构篇系列文章:
深入分析Kafka架构(一):工作流程、存储机制、分区策略
深入分析Kafka架构(二):数据可靠性、故障处理
深入分析Kafka架构(三):消费者消费方式、三种分区分配策略、offset维护
因此我觉得非常有必要再辅以代码实现,来加深理解,融会贯通。因此本系列kafka实战篇以实战为主,目的是使用kafka提供的JAVA API来完成消息的发送,消费,拦截等操作,用来加深对kafka架构的认知,并会把相关完整demo共享到github和咱们csdn上,感兴趣的可以拿来使用。
本文为kafka实战系列第一篇,主要进行kafka的消息发送部分的流程解析及实战开发。
注意:我所使用的kafka版本为2.4.1,java版本为1.8,本文会对一些新老版本的改动地方加以说明。
二、调试常用命令行总结
其实在日常使用kafka的过程中,很少使用命令行操作,一般命令行操作只是用来调试的时候使用。不过作为回顾,下面列出一些常用的命令行操作,并对其进行详细解释。
-
查看当前服务器中的所有topic
bin/kafka-topics.sh --zookeeper zookeeper主机名或ip:2181 --list
-
创建topic
如下命令可以创建了一个3分区,2副本的topic first:
``` bin/kafka-topics.sh --zookeeper zookeeper主机名或ip:2181 \ --create --replication-factor 2 --partitions 3 --topic first 选项说明: --topic 定义topic名 --replication-factor 定义副本数 --partitions 定义分区数 ```
-
删除topic
注意:删除topic的时候需要在server.properties中设置delete.topic.enable=true否则只是标记删除,并没有真正删除。
bin/kafka-topics.sh --zookeeper zookeeper主机名或ip:2181 \ --delete --topic first
-
查看某个Topic的详情
bin/kafka-topics.sh --zookeeper zookeeper主机名或ip:2181 \ --describe --topic first
-
发送消息
注意:–broker-list kafka集群里的broker主机名或ip:9092,如果要发送给多个broker,用逗号分割就可以了。
bin/kafka-console-producer.sh \ --broker-list kafka集群里的broker主机名或ip:9092 --topic first 输入完上面的命令成功后会有">"标志,就可以输入数据了 输入数据,需要删除的时候按住ctrl 在点击backspace就可以删除了。 >hello world
-
消费消息
注意:在kafka0.9.x版本之前,消费者指定的是zookeeper,但是新版本都是指定的kafka集群。
bin/kafka-console-consumer.sh \ --bootstrap-server kafka集群里的broker主机名或ip:9092 --from-beginning --topic first --from-beginning:会把主题中以往所有的数据都读取出来。
-
修改分区数
注意:分区数只能增多不能减少(由于分区数减少后,把删掉的分区的数据分配到剩余的分区这个过程过于复杂,所以kafka没有设计分区减少的逻辑。)
``` bin/kafka-topics.sh --zookeeper zookeeper主机名或ip:2181 --alter --topic first --partitions 6 ```
三、Producer消息发送流程详解
3.1、总体流程
我们谈到消息队列就会想到:异步,解耦,消峰。kafka自然也不例外,在新版本里,它的Producer发送消息采用的也是异步发送的方式(之前老版本有同步发送的api,新版本取消了,但是我们可以通过骚操作实现同步发送,后面会详细解释)。在消息发送的过程中,涉及到了两个线程,分别是main线程(又叫主线程)和sender线程,以及一个线程共享变量(可以理解为缓存)RecordAccumulator。
总体来说,sender线程是main线程的守护线程,在工作时,main线程负责创建消息对象并将消息放在缓存RecordAccumulator,sender线程从缓存RecordAccumulator中拉取消息然后发送到kafka broker。
关于RecordAccumulator,咱们还需要知道:
- 在消息追加到RecordAccumulator时会对消息进行分类,发往同一分区的消息会被装在同一个Deque中,Deque存放的是ProducerBatch表示一组消息。换句话说就是RecordAccumulator会按照分区进行队列维护;
- 队列中存放的是发往该分区的消息组,追加消息时候从队列的尾部追加;
- RecordAccumulator的大小默认32M,可以通过buffer.memory配置指定;
- 如果内存空间用完了,追加消息将发生阻塞直到有空间可用为止,默认最大阻塞60s,可以通过数max.block.ms配置。
整体流程图可以看成下面这样:
其实知道了上面这些,就可以根据api写一些简单的kafka发送消息的代码了。因为在api里,main线程和sender线程都被封装的很好,很多事情是我们不需要去关心的。
不过如果你和我一样,好奇main线程和sender线程具体都做了什么?那就接着看下面这部分细化的的流程总结,不感兴趣的话就可以直接跳到下一大节(异步发送Demo)开始撸代码了。
3.2、分步骤细化流程
首先main线程的流程:
- 封装消息对象为ProducerRecord并调用send方法;
- 进入producer拦截器(拦截器可以自定义);
- 更新kafka集群数据;
- 进行序列化,将消息对象序列化成byte数组;
- 使用分区器计算分区;
- 将消息追加到线程共享变量RecordAccumulator。
sender线程在KafkaProduer实例化结束开启,后面就是sender线程干的活了:
- sender线程将消息从RecordAccumulator中取出处理消息格式;
- 构建发送的请求对象Request;
- 将请求交给Selector,并将请求存放在请求队列;
- 收到响应就移除请求队列的请求,调用每个消息上的回调函数。
四、异步发送消息实战
其实只要掌握了Producer消息发送的总体流程,就可以根据api写基本demo了。下面我们层层递进来完成异步发送demo。
4.1、引入依赖
这里以maven依赖为例,大家可以根据自己的kafka版本在mvn上找到适合自己的依赖,由于只是做简单的消息发送,所以只需要引入kafka-clients依赖即可。我的kafka版本为2.4.1,所以我需要引入的依赖为:
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</