Kfka的学习
一、Kafka概述
1.1 定义
Kafka的定义:Kafka是一个分布式的基于发布/订阅模式的消息队列,主要应用于大数据实时处理领域。
1.2 消息队列
传统的消息队列的主要应用场景包括:缓存/消峰、解耦和异步通信。
消息队列的两种模式
- 点对点模式
- 消息/订阅模式
二、Kafka入门
2.1 Kafka安装部署
2.1.1 集群部署
1. 首先下载安装包。在hadoop102虚拟机上上传 kafka_2.12-3.0.0.tgz 的安装包,然后输入命令:tar -zxvf kafka_2.12-3.0.0.tgz
,解压该安装包,解压完成后输入命令:mv kafka_2.12-3.0.0/ kafka-3.0.0/
,将其改名,然后进入到kafka中config目录下,修改文件 server.properties ,找到 Log Basic 模块,将log.dirs=/tmp/kafka-logs
修改为log.dirs=/opt/software/kafka-3.0.0/datas
,该datas目录需要提前创建,然后找到zookeeper模块,然后将zookeeper.connect=localhost:2181
属性修改为zookeeper.connect=hadoop102:2181,hadoop103:2181,hadoop103:2181/kafka
,修改完成后保存。然后在hadoop102虚拟机上输入命令:xsync kafka-3.0.0/
分发该文件。然后分别在hadoop103和104上的/opt/software/kafka-3.0.0/config
目录下修改 server.properties 文件,找到 ServerBasics 模块,分别将broker.id=0
修改为1和2,因为这个ID不能重复。
2. 下面开始配置环境变量。在hadoop102虚拟机上输入命令:vi /etc/profile.d/my_env.sh
,增加如下内容,设置完成后保存并退出,一定记得source /etc/profile
使其生效,然后hadoop103和104上也要按照上述步骤配置kafka的环境变量然后source。
#KAFKA_HOME export KAFKA_HOME=/opt/software/kafka-3.0.0 export PATH=$PATH:$KAFKA_HOME/bin
3. 然后开始启动kafka集群。注意启动kafka之前先把zookeeper集群启动起来,输入命令zk.sh start
,然后依次在Hadoop102,103,104主机上进入到kafka中输入命令:bin/kafka-server-start.sh -daemon config/server.properties
来启动kafka,关闭集群的话要分别在每个虚拟机上输入命令:bin/kafka-server-stop.sh
。
注意:kafka关闭需要两三秒钟,在关闭zookeeper集群之前一定要保证所有的kafka都正常关闭,如果kafka没关闭前,zookeeper集群关闭的话,那么Kafka的集群就一直停不了。
2.1.2 集群启停脚本
在Hadoop102虚拟机的 ~/bin/ 目录下,输入命令:vi kf.sh
,创建脚本,在该脚本内添加如下内容,然后输入命令:chmod 777 kf.sh
赋予该脚本执行权限。
#! /bin/bash case $1 in "start"){ for i in hadoop102 hadoop103 hadoop104 do 、 echo " --------启动 $i Kafka-------" ssh $i "/opt/software/kafka-3.0.0/bin/kafka-server-start.sh -daemon /opt/software/kafka-3.0.0/config/server.properties" done };; "stop"){ for i in hadoop102 hadoop103 hadoop104 do echo " --------停止 $i Kafka-------" ssh $i "/opt/software/kafka-3.0.0/bin/kafka-server-stop.sh " done };; esac
2.2 kafka命令行操作
2.2.1 主题命令行操作
输入命令:bin/kafka-topics.sh
,可以查看操作主题的命令参数。
2.2.2 生产者命令行操作
输入命令:bin/kafka-console-producer.sh
,可以查看操作生产者命令参数。
2.2.3 消费者命令行操作
输入命令:bin/kafka-console-consumer
查看消费者命令参数。
三、Kafka生产者
3.1 生产者消息发送流程
3.1.1 发送原理
3.1.2 重要参数列表
3.2 生产者分区
3.2.1 分区好处
(1)便于合理使用存储资源,每个Partition在一个Broker上存储,可以把海量的数据按照分区切割成一块一块数据存储在多台Broker上。合理控制分区的任务,可以实现负载均衡的效果。
(2)提高并行度,生产者可以以分区为单位发送数据;消费者可以以分区为单位进行消费数据。
3.2.2 生产者发送消息的分区策略
(1)指明partition的情况下,直接将指明的值作为partition值;
(2)没有指明partition值但有key的情况下,将key的hash值与topic的partition数进行取余得到partition值;
(3)既没有partition值又没有key值的情况下,Kafka采用Sticky Partition(黏性分区器),会随机选择一个分区,并尽可能一直使用该分区,待该分区的batch已满或者已完成,Kafka再随机一个分区进行使用(和上一次的分区不同)。
3.2.3 自定义分区
可以根据需求重新实现分区器。
3.3 生产经验
3.3.1 生产者如何提高吞吐量
可以修改如下几个参数:
- batch.size:批次大小,默认16k;
- linger.ms:等待时间,默认0;
- compression.type:压缩,默认 none,可配置值 gzip、snappy、lz4 和 zstd;
- RecordAccumulator:缓冲区大小,默认32M;
3.3.2 数据可靠性
acks=0,生产者发送过来数据就不管了,可靠性差,效率高;
acks=1,生产者发送过来数据Leader应答,可靠性中等,效率中等;
acks=-1(all),生产者发送过来数据Leader和ISR队列里面所有Follwer应答,可靠性高,效率低;(默认的)
在生产环境中,acks=0很少使用;acks=1,一般用于传输普通日志,允许丢个别数据;acks=-1,一般用于传输和钱相关的数据,对可靠性要求比较高的场景。
3.3.3 数据去重
1. 幂等性
幂等性就是指Producer不论向Broker发送多少次重复数据,Broker端都只会持久化一条,保证了不重复。(参数 enable.idempotence 默认为 true)
精确一次(Exactly Once) = 幂等性 + 至少一次( ack=-1 + 分区副本数>=2 + ISR最小副本数量>=2) 。
重复数据的判断标准:具有<PID, Partition, SeqNumber>相同主键的消息提交时,Broker只会持久化一条。其中PID是Kafka每次重启都会分配一个新的;Partition 表示分区号;Sequence Number是单调自增的。所以幂等性只能保证的是在单分区单会话内不重复。
2. 生产者事务
开启事务,必须开启幂等性。在使用事务功能前,必须先自定义一个唯一的 transactional.id。有了transactional.id,即使客户端挂掉了,它重启后也能继续处理未完成的事务。
3.3.4 数据有序
单分区内,有序(有条件的,详见下节);多分区,分区与分区间无序;
3.3.5 数据无序
1)kafka在1.x版本之前保证数据单分区有序,条件如下:max.in.flight.requests.per.connection=1
(不需要考虑是否开启幂等性)。
2)kafka在1.x及以后版本保证数据单分区有序,条件如下:
- 未开启幂等性:max.in.flight.requests.per.connection需要设置为1。
- 开启幂等性:max.in.flight.requests.per.connection需要设置小于等于5。
四、Kafka Broker
4.1 Kafka Broker 工作流程
4.2 生产经验
4.2.1 服役新节点
就是在集群中增加一个新节点,将该节点的broker.id按节点顺序修改好,启动原集群,然后启动新节点的kafka,创建一个要均衡的主题,生成一个负载均衡的计划,创建副本存储计划,最后执行,可以自行验证。
4.2.2 退役旧节点
即从集群中删除一个节点,同上述步骤大概相同,创建主题,执行计划,副本执行计划最后执行副本计划。
4.3 Kafka副本
4.3.1 副本基本信息
(1)Kafka 副本作用:提高数据可靠性。
(2)Kafka 默认副本 1 个,生产环境一般配置为 2 个,保证数据可靠性;太多副本会增加磁盘存储空间,增加网络上数据传输,降低效率。
(3)Kafka 中副本分为:Leader 和 Follower。Kafka 生产者只会把数据发往 Leader,然后 Follower 找 Leader 进行同步数据。
(4)Kafka 分区中的所有副本统称为 AR(Assigned Repllicas)。AR = ISR + OSR 。ISR,表示和 Leader 保持同步的 Follower 集合。如果 Follower 长时间未向 Leader 发送通信请求或同步数据,则该 Follower 将被踢出 ISR。该时间阈值由 replica.lag.time.max.ms 参数设定,默认 30s。Leader 发生故障之后,就会从 ISR 中选举新的 Leader。 OSR,表示 Follower 与 Leader 副本同步时,延迟过多的副本。
4.3.2 Leader选举流程
Kafka 集群中有一个 broker 的 Controller 会被选举为 Controller Leader,负责管理集群 broker 的上下线,所有 topic 的分区副本分配和 Leader 选举等工作。 Controller 的信息同步工作是依赖于 Zookeeper 的。
4.3.3 Leader 和 Follower 故障处理细节
LEO(Log End Offset):每个副本的最后一个offset,LEO其实就是最新的offset + 1。
HW(High Watermark):所有副本中最小的LEO 。
1. Follower故障
Follower发生故障后会被临时踢出ISR,这个期间Leader和Follower继续接收数据,待该Follower恢复后,Follower会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截取掉,从HW开始向Leader进行同步,等该Follower的LEO大于等于该Partition的HW,即Follower追上Leader之后,就可以重新加入ISR了。
2. Leader故障
Leader发生故障之后,会从ISR中选出一个新的Leader,为保证多个副本之间的数据一致性,其余的Follower会先
将各自的log文件高于HW的部分截掉,然后从新的Leader同步数据。注意:这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复。
4.3.4 分区副本分配
这个不太明白,感觉就是有规律的分配的,一会都跳一个一会都跳两个。
4.3.5 生产经验
1. 手动调整分区副本存储
在生产环境中,每台服务器的配置和性能不一致,但是Kafka只会根据自己的代码规则创建对应的分区副本,就会导致个别服务器存储压力较大。所有需要手动调整分区副本的存储。
2. Leader Partition 负载平衡
注:建议不要开启自平衡,因为每次的调整都要耗费大量资源,如果一定要开启为true的话也要记得把触发调整的不平衡比率调整大些。
3. 增加副本因子
在生产环境当中,由于某个主题的重要等级需要提升,我们考虑增加副本。副本数的增加需要先制定计划,然后根据计划执行。
4.4 文件存储
4.4.1 文件存储机制
Topic是逻辑上的概念,而partition是物理上的概念,每个partition对应于一个log文件,该log文件中存储的就是Producer生产的数据。Producer生产的数据会被不断追加到该log文件末端,为防止log文件过大导致数据定位效率低下,Kafka采取了分片和索引机制,将每个partition分为多个segment。每个segment包括:“.index”文件、“.log”文件和.timeindex等文件。.log是日志文件,.index是偏移量索引文件,.timeindex是时间戳索引文件。
注意:
- index为稀疏索引,大约每往log文件写入4kb数据,会往index文件写入一条索引。参数log.index.interval.bytes默认4kb。
- Index文件中保存的offset为相对offset,这样能确保offset的值所占空间不会过大,因此能将offset的值控制在固定大小
日志存储的参数配置:
4.4.2 文件清理策略
1. Kafka 中默认的日志保存时间为 7 天,可以通过调整如下参数修改保存时间。
- log.retention.hours,最低优先级小时,默认 7 天。
- log.retention.minutes,分钟。
- log.retention.ms,最高优先级毫秒。
- log.retention.check.interval.ms,负责设置检查周期,默认 5 分钟。
2. Kafka 中提供的日志清理策略有 delete 和 compact 两种。 - delete 日志删除:将过期数据删除
log.cleanup.policy = delete
所有数据启用删除策略
(1)基于时间:默认打开。以 segment 中所有记录中的最晚时间戳作为该文件时间戳。
(2)基于大小:默认关闭。超过设置的所有日志总大小,删除最早的 segment。log.retention.bytes,默认等于-1,表示无穷大。 - compact 日志压缩
log.cleanup.policy = compact
所有数据启用压缩策略,对于相同key的不同value值,只保留最后(最新)一个版本。
4.5 高效读写数据
1)Kafka 本身是分布式集群,可以采用分区技术,并行度高;
2)读数据采用稀疏索引,可以快速定位要消费的数据;
3)顺序写磁盘,省去了大量磁头寻址的时间;
4)页缓存 + 零拷贝技术 ,Kafka的数据加工处理操作交由Kafka生产者和Kafka消费者处理。Kafka Broker应用层不关心存储的数据,所以就不用走应用层,传输效率高。
五、Kafka消费者
5.1 Kafka 消费方式
- pull(拉)模式:consumer从broker中主动拉取数据。Kafka采用的就是这种方式,这种方式的不足之处是:如果Kafka没有数据,消费者可能会陷入循环中,一直返回空数据。
- push(推)模式:Kafka没有采用这种方式,因为由broker决定消息发送速率,很难适应所有消费者的消费速率。
5.2 Kafka 消费者工作流程
5.2.1 消费者总体工作流程
5.2.2 消费者组原理
1. 消费者组
Consumer Group(CG):消费者组,由多个consumer组成。形成一个消费者组的条件,是所有消费者的groupid相同。
- 消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费。
- 消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
2. 消费者组初始化流程
coordinator:辅助实现消费者组的初始化和分区的分配。coordinator节点选择 = groupid的hashcode值 % 50( __consumer_offsets的分区数量)。
3. 消费者组消费流程
5.2.3 消费者重要参数
5.3 生产经验——分区的分配以及再平衡
Kafka有四种主流的分区分配策略: Range、RoundRobin、Sticky、CooperativeSticky。可以通过配置参数partition.assignment.strategy,修改分区的分配策略。默认策略是Range + CooperativeSticky。Kafka可以同时使用多个分区分配策略。
5.3.1 Range 以及再平衡
1. Range 分区策略原理
Range 是对每个 topic 而言的。首先对同一个 topic 里面的分区按照序号进行排序,并对消费者按照字母顺序进行排序。通过 partitions数/consumer数 来决定每个消费者应该消费几个分区。如果除不尽,那么前面几个消费者将会多消费 1 个分区。
注意:如果只是针对 1 个 topic 而言,C0消费者多消费1个分区影响不是很大。但是如果有 N 多个 topic,那么针对每个 topic,消费者 C0都将多消费 1 个分区,topic越多,C0消费的分区会比其他消费者明显多消费 N 个分区。所以这种分区策略的缺点是:容易产生数据倾斜。
2. Range 再平衡策略
当某个消费者挂掉后,消费者组需要按照超时时间 45s 来判断它是否退出,所以需
要等待 45s ,在这 45s 期间,该挂掉的消费者的任务会被整体分配到其它消费者上,若超过 45 秒后,该挂掉的消费者会被踢出消费者组,所有任务重新按照 range 方式分配。
5.3.2 RoundRobin 以及再平衡
1. RoundRobin 分区策略原理
RoundRobin 针对集群中所有Topic而言。RoundRobin 轮询分区策略,是把所有的 partition 和所有的consumer 都列出来,然后按照 hashcode 进行排序,最后
通过轮询算法来分配 partition 给到各个消费者。
2. RoundRobin 再平衡策略
当某个消费者挂掉后消费者组需要按照超时时间 45s 来判断它是否退出,在 45s 期间,会把该挂掉的消费者的任务按照轮询的方式分配给其它消费者,时间到了 45s 后,该挂掉的消费者会被踢出消费者组,所有任务重新按照 RoundRobin 方式分配。
5.3.3 Sticky 以及再平衡
1. Sticky 分区策略原理
粘性分区:可以理解为分配的结果带有“粘性的”。即在执行一次新的分配之前,考虑上一次分配的结果,尽量少的调整分配的变动,可以节省大量的开销。
粘性分区是 Kafka 从 0.11.x 版本开始引入这种分配策略,首先会尽量均衡而且随机的放置分区到消费者上面,在出现同一消费者组内消费者出现问题的时候,会尽量保持原有分配的分区不变化。
2. Sticky 再平衡策略
当某个消费者挂掉后消费者组需要按照超时时间 45s 来判断它是否退出,在 45s 期间,会把该挂掉的消费者的任务按照粘性规则,尽可能均衡的随机分配到其它消费者上,时间到了 45s 后,该挂掉的消费者会被踢出消费者组,所有任务重新按照粘性方式方式分配。
5.4 offset 位移
5.4.1 offset 的默认维护位置
Kafka 0.9版本之前,consumer默认将offset保存在Zookeeper中,从0.9版本开始,consumer默认将offset保存在Kafka一个内置的topic中,该topic为__consumer_offsets 。每隔一段时间,kafka 内部会对这个 topic 进行compact,也就是每个 group.id+topic+分区号就保留最新数据。
5.4.2 自动提交offset
为了使我们能够专注于自己的业务逻辑,Kafka提供了自动提交offset的功能。
自动提交offset的相关参数:
- enable.auto.commit:是否开启自动提交offset功能,默认是true
- auto.commit.interval.ms:自动提交offset的时间间隔,默认是5s
5.4.3 手动提交 offset
Kafka提供了手动提交offset的API,手动提交offset的方法有两种:分别是commitSync(同步提交)和commitAsync(异步提交)。两者的相同点是,都会将本次提交的一批数据最高的偏移量提交;不同点是,同步提交阻塞当前线程,一直到提交成
功,并且会自动失败重试(由不可控因素导致,也会出现提交失败);而异步提交则没有失败重试机制,故有可能提交失败。但更多的情况下,会选用异步提交 offset 的方式。
5.4.4 指定 Offset 消费
auto.offset.reset = earliest | latest | none 默认是 latest。
(1)earliest:自动将偏移量重置为最早的偏移量,--from-beginning。
(2)latest(默认值):自动将偏移量重置为最新偏移量。
(3)none:如果未找到消费者组的先前偏移量,则向消费者抛出异常。
(4)任意指定 offset 位置开始消费。
5.4.5 指定时间消费
在生产环境中,会遇到最近消费的几个小时数据异常,需要重新按照时间消费。
5.4.6 漏消费和重复消费
重复消费:已经消费了部分的数据,但是 offset 没提交消费者就挂机的情况。
漏消费:提交了offset但是并没有来得及消费数据,消费者就出现了问题挂机的情况,有可能会造成数据的漏消费。
5.5 生产经验
5.5.1 消费者事务
要想完成Consumer端的精准一次性消费,那么需要Kafka消费端将消费过程和提交offset过程做原子绑定。此时我们需要将Kafka的offset保存到支持事务的自定义介质(比如MySQL)。下游消费者必须支持事务,才能做到精确一次性消费。
5.5.2 数据积压(消费者如何提高吞吐量)
1. 如果是Kafka消费能力不足,则可以考虑增加Topic的分区数,并且同时提升消费组的消费者数量,消费者数 = 分区数。(两者缺一不可)
2. 如果是下游的数据处理不及时:提高每批次拉取的数量。批次拉取数据过少(拉取数据/处理时间 < 生产速度),使处理的数据小于生产的数据,也会造成数据积压。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?