kafka
传统定义:
分布式的基于发布/订阅模式的消息队列,主要用于大数据实时处理领域
发布订阅:消息的发布者,不会讲消息直接发给特定的订阅者,而是将发布的消息分为不同的类别,
订阅者只需要接收感兴趣的消息
最新定义:
kafka是一个开源的分布式事件流平台,可用于高性能数据管道,流分析,数据集成,关键任务应用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2CiMR3tv-1659417546707)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220713212235537.png)]
传统的消息队列应用场景
缓存/消峰、解耦、异步通信
缓存/消峰:
帮助控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致问题
原本用户的每次请求都会直接发送到系统,系统瞬时有了很大的数据需要处理,可能会导致系统出现各种问题
使用消息队列之后,用户的请求会先发送到消息队列,然后再由消息队列交由系统处理,这样就可以做到消峰处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mRfyKoLx-1659417546708)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220713213211365.png)]
解耦
只需要保证遵守同样的接口,就会允许独立的拓展或修改两边的处理过程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K7VzTZBp-1659417546708)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220713213559323.png)]
异步通信
允许用户将信息放入大搜队列中,但是并不立即处理,在需要的时候再去处理,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5X59sVik-1659417546708)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220713213656087.png)]
两种通信模式
点对点模式
消费者主动的拉取数据,消费者处理完成之后会给队列反馈,队列收到之后会将数据清除
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-izpBjCib-1659417546709)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220713214039163.png)]
该通信模式,队列只能有一个主题
发布订阅模式
可以有多个主题(分类),消费者消费数据之后,不删除数据,每个消费者相互独立,都可以消费数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qEPxTQLP-1659417546709)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220713214303753.png)]
消费者主动拉取数据完成之后,MQ并不会主动将数据删除,且每个消费者相互独立,都可以消费数据,
且MQ中可以有多个主题(分类)的数据
kafka基础框架
当数据向kafka消息队列中存储的时候,并不是直接一下将全部的数据都存入,为了方便拓展,提高吞吐量,数据的一个topic(分类)会分为多个partition分区
同时呢,为了配合分区的存在,对消费者也进行了一些的约束,就是一个分区只能由一个消费者来消费,以防止数据的混乱
为了防止partition分区中数据的丢失,kafka为每个分区增加了若干的副本,类似于主从复制,放分区中的数据丢失之后,会由副本顶上
其中由zookeeper来记录谁是leader,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lhb1xOYj-1659417546710)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220713220201808.png)]
(1) Producer:消息生产者,就是向 Kafka broker 发消息的客户端。
(2) Consumer:消息消费者,向 Kafka broker 取消息的客户端。
(3) Consumer Group(CG):消费者组,由多个 consumer 组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
(4) Broker:一台 Kafka 服务器就是一个 broker。一个集群由多个 broker 组成。一个 broker 可以容纳多个 topic。
(5) Topic:可以理解为一个队列,生产者和消费者面向的都是一个 topic。
(6) Partition:为了实现扩展性,一个非常大的 topic 可以分布到多个 broker(即服务器)上,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列。
(7) Replica:副本。一个 topic 的每个分区都有若干个副本,一个 Leader 和若干个Follower副本。
(8) Leader:每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是 Leader。
(9) Follower:每个分区多个副本中的“从”,实时从 Leader 中同步数据,保持和
Leader 数据的同步。Leader 发生故障时,某个 Follower 会成为新的 Leader。
生产者
生产者原理—数据发送的流程
在发送的过程中,主要涉及到了两个线程, main线程和sender线程
main线程中会创建一个双端队列RecordAccumulator,
main线程将数据消息发送到双端队列中,
sender线程从双端队列RecordAccumulator中拉取数据,发送到kafka broker中,就是kafka的服务器中
细分的话
main线程中的消息数据,会经过拦截器,以及序列化器,经过分区器将数据分到双端队列中的不同的子队列中
其中,双端队列RecordAccumulator的默认存储空间大小为32m,子队列默认为16kb大小,
当子队列的数据累计大小达到batch.size之后,sender线程才会拉取数据,默认为16kb
当sender线程等待时间超过lenger.ms等待时间之后,就会直接拉取子队列中的数据,忽视batch.size,默认值为0ms,需灵活更改
当数据存储到子队列DQuene中时,会有一个标记用于指定该数据发向哪一个broker
sender线程拉取数据之后,会根据消息数据上的broker标记,发送到对应的broker中,
当一个消息数据发送到broker之后,即使没有接收到反馈,也可发送后边的数据,类似于滑动窗口机制,当累计达到五个消息数据发送之后仍然没有接收到反馈,就会停止发送,直至接收到反馈
selector充当就是一个打通链路的关键位置,使得消息数据可以发送到broker中
broker接受处理数据之后会给selector发送一个ack,供与判断数据的处理情况
ack有如下几种
0: 表示生产者发送来的数据,不需要等待应答,–就是生产者不用管了
1: 生产者发送来的数据,leader收到数据之后需要发送应答就是kafka服务器收到数据之后,需要给sender线程一个响应
-1(all):生产者发送来的数据,leader和isr队列里面的所有节点收齐数据之后应答
select接收到应答之后,如果成功就清理掉队列中的缓存,如果没有就retry重新发送,相当于是死磕
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WTXcu0mn-1659417546710)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220714232535955.png)]
异步发送
异步发送指的是将外部数据发送到双端队列中,
就是不用等待双端队列中的数据处理完成之后,才向其发送数据,一直发送即可,不用等待反馈
在java程序中引入jar包之后,按照流程创建kafka生产者配置对象,序列化、创建生产者对象、调用send方法、关闭资源就是异步发送
在kafka中就可以看到send发送的数据了
带回调函数的异步发送
回调函数会在生产者 接收到ack时调用、为异步调用、
主要有两个参数,分别是原数据信息,异常信息
- 如果异常信息为空,就说明信息发送成功,
- 否则,说明消息发送失败
- 消息发送失败会自动重试,不需要我们在回调函数中手动重试。
同步发送API
在异步发送的基础上,调用get()方法即可
// 异步发送 默认
// kafkaProducer.send(new
ProducerRecord<>("first","kafka" + i));
// 同步发送
kafkaProducer.send(new
ProducerRecord<>("first","kafka" + i)).get();
生产者分区
分区的好处
便于合理使用存储资源,每个partition分区在一个Broker上存储,可以把海量的数据分区切割成一块一块的数据存储在多台Broker上,合理控制分区的任务可以实现负载均衡的效果
就是将大量的数据分发到不同的kafka服务器上进行存储,每台kafka服务器,又会进一步的整理数据
- 可以提高并行度,
- 生产者可以以分区为单位发送数据
- 消费者可以以分区为单位消费数据
- 生产者可以以分区为单位发送数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ozyTkQvn-1659417546711)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220716153755356.png)]
生产者发送消息的分区策略
默认的分区器 DefaultPartitioner
- 指明partition的情况下,直接将指明的值作为partition的值
- 没有指明partition值,但是有key的情况下,将key的hash值与topic的partition数量值进行取余得到partition值
- 没有有指明partition值,也没有key的情况下,kafka采用的是 sticky partition(粘性分区器),随机的选择一个分区,然后进行尽可能的一直使用该分区,待该分区的batch缓存已满或者已完成缓存了,kafka就再随机选择一个分区进行使用,(和上个使用的分区不同)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6GUZEg5F-1659417546711)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220716154958925.png)]
自定义分区器
定义类,实现partition接口, 重写partition方法
提高吞吐量
可以灵活的调节batch。size 缓存的大小
以及调节linger,ms等待时间
也可以使用压缩.compression。type 压缩snappy
调节缓冲区的大小 RecordAccumulator
数据的可靠性
ACK的应答级别
0:生产者发送来的数据不需要kafka服务器收到之后的反馈应答
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xqNGIWFR-1659417546712)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220716175409573.png)]
缺点:数据就算丢失了,生产者也不知道
可靠性差,效率高
1:生产者发送的数据,leader接受之后,返给生产者应答
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YgQx369W-1659417546713)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220716175517399.png)]
缺点: leader接收到了数据,但是还没来得及将数据备份到follower上就挂了,导致数据会丢失
可靠性中等,效率中等
-1: (all ) 生产者发送的数据,leader和follower都存储好数据之后才给生产者反馈应答
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G5gVQbVv-1659417546713)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220716175716484.png)]
思考: leader接收之后其备份follower在备份的过程中挂掉了,就会导致迟迟无法向生产者反馈
leader维护了一个动态的 ISR,作用就是和leader保持同步的Follower+leader集合
eg: (leader: 0, isr:0,1,2)
如果follower长时间没有向leader发送通信请求或同步数据,则该Follower就会被踢出ISR
这个时间阈值由,replica.lag.time.max.ms 参数设定,默认为30s
就例如 2 超时了 , (leader: 0, isr:0,1)
这样就不用长时间的等待联系不上或者已经故障的节点
数据可靠性分析:
如果分区副本设置1,或者ISR中应答的最小副本数量设为1.则和ack=1的效果是一样的,仍然会有丢失数据的风险
数据完全可靠的条件=ACK级别设置为-1 + 分区副本大于等于2 + ISR里应答的最小副本数量大于等于2
生产者发送来的数据leader和ISR队列中所有Follower应答可靠性高,效率低
会有数据重复的可能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fktjqlUC-1659417546713)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220716181222018.png)]
数据传递
至少一次(At least Once )= ACK级别设置为-1 + 分区副本大于等于2 + ISR里应答的最小副本数量大于等于2
最多一次(At Most Once) =ACK级别设为0
总结:
至少一次可以保证数据不丢失,但是不能保证数据不重复
最多一次,可以保证数据不重复,但是不能保证数据不丢失
精确一次:对于重要的消息,需要求数据既不能重复也不能丢失
这个就是和幂等性和事务相关了
幂等性
就是指生产者不论向Broker发送多少次重复数据, Broker端只会持久化一个保证了数据的不重复
精确一次=幂等性+至少一次(ACK级别设置为-1 + 分区副本>=2 + ISR里应答的最小副本数量大于等于2)
重复数据的判断标准: 具有《PID,partition,seqNumber》 相同主键的消息提交时,Broker只会持久化一个,
其中PID是生产者的id,partition表示分区号,seqNumber是单调自增的
所以幂等性保证的是在单分区单会话内不重复 只能保证单会话内不重复,就是每次启动,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aBKkeEYw-1659417546714)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220716183739570.png)]
如何使用幂等性 __开启参数 enable.idempotence 默认为 true,false 关闭。
事务
开启事务,就必须开启幂等性
每个Broker中 ,也就是每个kafka中,
会有事务协调器 ,不同分区的leader,还有存储事务信息的特殊主题
-
一般默认会有五十个分区,每个分区负责一部分事务
- 事务的划分是根据transactional.ld的hashcode值的50%,从而可以计算出该事务属于哪个分区,
- 然后这个分区leader副本所在的Broker节点,transactional.ld对应的事务协调器节点
-
就是在存储事务信息的主题中找到事务对应的分区节点,然后通过该分区节点,找到对应的事务协调器
- 事务协调器就是本次执行事务的主负责人
-
生产者producer在使用事务功能前,就必须先自定义一个惟一的transactional.ld
- 有了这个标识,即使客户端挂掉了,重启之后也能够继续处理未完成的事务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3scRA7iY-1659417546714)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220720203452576.png)]
- 首先,生产者会先向事务协调器发起一个请求 ,获取transactional.ld
- 事务协调器就会向生产者返回请求的数据transactional.ld
- 然后生产者向kafka集群中的指定broker的分区发送数据
- 发送数据之后,生产者会向事务协调器发起commit请求,以求将数据持久化
- 事务协调器收到commit请求之后,会向存储事务信息的特殊主题发送持久化数据的commit请求
- 协调器发送之后就先会给生产者发送返回成功的消息
- 然后再由事务协调器向分区的leader发送将数据持久化的commit请求,
- 分区leader将数据持久化之后,会给协调器返回成功信息
- 事务协调器再向存储事务信息的特殊主题返回成功信息
- 至此一次事务commit结束
一次事务,发送三次commit,返回三次成功信息,生产者将数据发送到指定broker的分区之后,事情就交给事务协调器来处理。
真真就是协调器,来回传话
数据有序
因为数据从生产者发送到消费者的过程中,会先发送到kafka不同的分区中,这也就导致了取回数据消费时,数据是一个无序的状态
解决方法
- 单个分区,单分区内有序
- 多个分区,分区与分区之间的数据是无序的,但是可以在消费者拉取数据之后,先不消费,先存储到某个区域排序之后,有序了在消费处理数据。
数据的乱序
产生原因
- 生产者向每个broker发送数据是,会先缓存五个请求,类似于滑动窗口
- 例如缓存1,2,3,4,5 五个数据,开始向broker发送
- 1,2,发送成功,但是3发送失败,但是此时生产者并不知道3发送失败了,会继续发送4,5 最终发现3失败,就会再次的传递3。这也就导致了数据的顺序是 12453,和源数据顺序不相同, 出现了乱序的情况
- 例如缓存1,2,3,4,5 五个数据,开始向broker发送
解决方案
- kafka在1.x之前保证单分区数据有序
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LhUQph4A-1659417546715)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220720210314464.png)]
- kakfka在1.x之前保证单分区有效
- 分两种情况,开启幂等性和未开启幂等性
- 未开启幂等性
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FQISe9cn-1659417546715)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220720210512997.png)]
- 开启幂等性
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-86KMUiso-1659417546715)(C:\Users\Lenovo\Desktop\学习记录\数据库\关系型数据库\image-20220720210535802.png)]
- 开启幂等性之后,数据会有一个pid的标识,其中有一项就是数据的seqNumber是数据存储的顺序,为单调递增,当kafka收到数据的序号不对,就不会将数据落盘存储,而是等到对的数据序号,将其按原位置存储好之后,再存储之前已经发送来但是为存储的数据,这样就可以保障数据的有序了
Broker
zookeeper中存储的kafka的信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9xy5ZMjM-1659417546717)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220720211634457.png)]
controller,谁先拿到注册权,
kafka Broker的工作流程
- 首先 broker启动后在zk中注册
- 然后由kafka集群中的Broker抢夺controller的注册权,谁先抢到,谁就说的算
- 选举出来的Controller来侦听brokers的节点变化
- 然后由controller决定每个broker中的leader和followers
- 选举规则:以在isr中存活为前提,按照AR(分区中所有副本的统称)排在前面的优先
- 例如 ar【1,0,2】,isr【1,0,2】leader的顺序就会按照102的顺序来轮询
- 选举规则:以在isr中存活为前提,按照AR(分区中所有副本的统称)排在前面的优先
- 再然后由controller将节点的信息上传到zk中
- 同时,其他各个broker中的controller从zk中同步相关的消息,做好随时上位的准备_
- 如果broker中的leader挂了,就会被controller侦听到,然后获取isr 按照AR进行选取新的leader
- 更新zk中的leader和isr的信息,将各个broker中的信息从zk中进行同步
生产者向kafka的broker发送信息之后,数据会先存储在leader中,然followers会主动的与leader同步信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pe5o8tfH-1659417546717)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220720214753700.png)]
controller主要依靠ZK完成对集群broker和分区的管理如集群broker信息、分区选举ISR
副本
副本的作用:提高数据可靠性
kafka默认副本只有1个,生产环境一般配置两个副本,来保证数据的可靠性,太多的副本会占用外的磁盘空间,增加了网络上的数据传输,变相的降低了效率
- kafka中的副本,分为leader和follower
- kafka的生产者只会把数据发往leader,然后follower会找leader同步数据
- kafka分区中的所有副本统称AR
- AR=ISR+OSR
- ISR表示和leader保持同步的follower的集合
- 如果Follower长时间没有向leader发送通信请求或同步数据,这个follower就会被踢出ISR,默认时间为30s,
- leader发生故障之后,就会从ISR中选举新的leader
- 如果Follower长时间没有向leader发送通信请求或同步数据,这个follower就会被踢出ISR,默认时间为30s,
- OSR,表示Follower和leader副本同步时,延迟过多的副本
- ISR表示和leader保持同步的follower的集合
- AR=ISR+OSR
leader的选举流程
首先在kafka服务器在zk中挂载注册之后,会由各个kafka broker在zk中争抢controller的控制权,谁先注册到谁说的算,然后选取出来的controller会侦听各个broker节点的变化,
各个broker中按照isr中的存活顺序,首个副本充当leader,如果leader挂掉之后,依次轮询
然后controller将节点的信息同步上传到zk
其他各个broker中的controller从zk中同步相关信息
如果leader挂了,执行上述步骤,更新leader,同步信息到zk,从zk中同步信息到broker中的controller
Follower故障处理细节
LEO(Log End Offset) : 每个副本的最后一个offset,leo就是最新的offset+1
HW(HIGH Watermark): 所有副本最小的LEO
Follower故障
-
follower发送故障之后会被踢出ISR
-
这个期间leader和follower继续接收数据
-
等到该follower恢复之后,Follower会读取本地磁盘中的上个hw位置的文件,并将高于hw部分截取掉,从hw开始向leader进行同步
-
等该Follower的LEO大于等于该Partition的HW,就是等数据同步追赶上leader之后,再次重新加入到ISR中
leader故障处理细节
leader发生故障之后,会从follower中选取出一个新的leader
为了保证副本数据的一致性,会将其余所有副本高于新leader的hw的部分去除,然后从新的leader中同步数据
这也就是说明,只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5emyOEOI-1659417546718)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220721213558655.png)]
Leader Partition自动平衡
一般不会开启
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x0otBiMk-1659417546718)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220721220021496.png)]
kafka文件存储机制
topic是逻辑上的概念,一个topic可以分为多个分区
partition是物理上的概念,每一个partition对应着一个log文件,
这个log文件中存储的就是producer生产者生成的数据
Producer生成的数据会被不断地追加到该log文件的末端,为了防止log文件过大,导致数据定位效率低下,
kafka采取了分片和索引机制,将每个partition分为多个segment。
每个segment包括".index 文件" 偏移量索引文件,“.log 文件” 日志文件 和timeIndex文件 时间戳索引文件等
这些文件的命名规则为topic 名称+分区序号 如 first-0
注意 ,index为稀疏索引,大约每向log文件存储4kb的数据,就可以向index文件写入一条索引
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o4Pw65RS-1659417546718)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220721221325248.png)]
文件清除策略
kafka中默认的日志保存时间为7天,可以通过调整对应的参数来调整保存时间
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kOaGqnk6-1659417546718)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220721222419873.png)]
一旦超过了设置的时间,日志的清理策略就有两种
delete 和compact
delete 是将日志删除,将过期的数据删除 (默认)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-krjc3mNd-1659417546719)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220721222538311.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QocBia9t-1659417546719)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220721222811342.png)]
compact 压缩日志
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wBCWDZKR-1659417546719)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220721223022883.png)]
高效读写数据
kafka本身是分布式集群,多台服务器处理一件事情,速度当然会快很多
也可以采用分区技术(提高并行度),并行度高
读数据 采用的是稀疏索引,可以快速定位要消费的数据
写入数据时,采用的是顺序写磁盘,生产传入的数据时一直追加到文件的末端的,省去了大量磁头寻址时间
页缓存和零拷贝技术
当生产者发送数据到kafka之后,kafka会将数据先交给linux的内核 进行页缓存,
数据最终的落盘时间是由该内核决定的,kafka不用管
pageCache页缓存
kafka重度依赖于底层操作系统提供的pageCache功能,当上层有写操作时,操作系统只是将数据写入pageCache,其他的落盘操作都交由操作系统控制完成了,
当上层发生读操作时,先从pageCache中查找,如果找不到,在向磁盘中读取,实际上呢pageCache是尽可能的把磁盘中尽可能多的空闲内存都当做磁盘缓存来使用。
零拷贝
kafka的数据加工处理操作交由kafka生产者和kafka消费者来处理的, kafka Broker应用层并不关心存储的数据,所以就不用走kafka的应用层,传输效率就会高很多。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wBuKpgx2-1659417546720)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220721225129844.png)]
非零拷贝做对比
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3naIDqm0-1659417546720)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220721225151684.png)]
消费者
消费方式
pull 拉模式————kafka所采用的的形式
消费者采用从broker中主动拉取数据,消费者的处理速度由他自己决定
不足之处是,如果kafka没有数据,消费者可能会陷入循环中,一直返回空数据
push 推 模式
有服务器决定消息数据的发送速率,不能适应所有的消费者的消费速率
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pzuedXlV-1659417546720)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220725210958572.png)]
消费者总体工作流程
当数据由生产者发送到kafka服务器,并且做好同步工作之后,消费者会主动的向分区请求拉取数据,单个的消费者可以消费多个不同分区的数据,且不会产生影响
但是要注意每个分区的数据只能由消费者组中的一个消费者消费
消费者组内的每个消费者只能消费各自不同分区的数据
当消费者挂掉之后,如果还想要从上次读取数据之后的位置开始拉取数据,这就涉及到了偏移量 offset, 这个变量是交由kafka中的主题来保存的,而不是保存在zk中,以此来避免网络中有频繁的数据交互,、
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WBhydgtw-1659417546720)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220725211616997.png)]
消费者组
消费者组,是由多个consumer组成,形成一个消费者组的条件是所有消费者的groupid相同
消费者组内的每一个消费者负责消费不同区域的数据,一个分区只能由一个组内消费者来消费,
消费者之间是互不影响的,
所有的消费者都属于某个消费者组,逻辑上所有的消费者都属于一个大的消费者,就是套娃
但是注意,消费者组之间是互不影响的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xkTNWIbt-1659417546721)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220725213558047.png)]
当一个组内的消费者数量高于kafka分区,就会导致有一部分的消费者闲置,不会接受任何消息,
多出来的消费者并不会去分摊其他消费者的压力,因为,一个消费者组内,的消费者所消费数据的分区是相互独立的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hp0Jmihr-1659417546721)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220725213730149.png)]
不同消费者组之间的数据是完全完全独立的
消费者组初始化的流程
消费者组合kafka集群之间的交互是通过coordinator辅助实现消费者组的初始化和分区的分配
coordinator节点的选择=groupid的hashcode值%50(-consumer-offset的分区数量)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cOvpwZq2-1659417546721)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220725215036885.png)]
首先每个consummer会发送加入消费者组的joinGroup请求。
然后经由coordinator随机选出消费者组中的一个consumer作为leader负责选区消费等工作
coordinator会把消费的topic情况发送给leader消费者
leader会指定消费者的消费方案,并且把该方案发送给coordinator
由coordinator负责吧消费方案发送给各个consumer
每个消费者都会和coordinator保持心跳,默认3s,一旦超时,该消费者就会被移除,并触发再平衡,或者消费者处理消息的是将过长,也会触发再平衡
(再平衡就是将broker分区的任务,重新分配消费者处理)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QTz1BRRw-1659417546722)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220725215051593.png)]
消费者组详细消费流程
消费者组想要消费数据,就需要先创建一个consumerNetworkClient,主要用来与kafka进行一个交互
消费者组向consumerNetworkClient发送sendFetches消费请求
经由consumerNetworkClient发向kafka,触发kafka中的onsuccess回调,将数据放到双端队列中,
消费者从双端队列中取出数据,然后经由反序列化、拦截器之后,开始处理数据
还可以对每次取回的数据大小做出设置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zcY4YEXZ-1659417546722)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220725220812058.png)]
分区的分配以及再平衡
一个consumer group 中有多个consumer组成,一个topic有多个partition组成
那么到底由哪个consumer来消费指定的partition中的数据呢,
这个是通过kafka的分区策略来实现的
分别是:Range、RoundRobin、Sticky、CooperativeSticy
可以通过配置参数partition.assignment.strategy 来修改分配策略
默认策略是Range+CooperativeSticy
kafka可以同时使用多个分区分配策略
Range
range是对每个topic而言的,首先对同一个topic中的分区按照序号进行排序,并且对消费者按照字母顺序进行排序
通过分区数/消费者数,来决定每个消费者应该消费几个分区,如果除不尽,前面的几个消费者将会多消费若干分区,平均分配
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lAqBC1h3-1659417546722)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220726223214240.png)]
但是注意,当topic数量过多,消费者数量较少,前面的c0消费者可能就会明显多于其他消费者的消费分区,会造成数据倾斜
RoundRObin
RoundRobin是针对集群中所有的Topic而言的
RoundRobin轮询分区策略,是把所有的partition和所有的consumer都列出来,然后按照hashcode进行排序,最后通过轮询算法来分配partition给到各个消费者
Sticky
粘性分区,就是每次分配的结果是带有粘性的,执行一次分配之后,如果想要在重新分配,就需要考虑上次分配的结果,尽量少的调整分配的变动,已到达节省大量开销
该策略会尽量均衡的将分区放置到消费者上面,分区数/消费者数 有点类似于Range
但是这个分区的排序是随机的,这点和range有区别
offset偏移量
0.9版本之后,消费者就会将offset保存在kafka中的一个内置topic中,(_comsumer_offsets)
0.9之前,是保存在zk中的
_comsumer_offsets主题中采用键值对的形式存储形式,key是group id+topic+分区号,value是当前的offset值,每隔一段时间,kafka内部就会对这个topic进行compact,所以每个key对应的值就是保留的最新数据
kafka可以自动的提交offset,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HayEulmA-1659417546722)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220726230256146.png)]
手动提交offset
自动提交虽然简单,但其是基于时间提交的,开发人员不能较好的把握offset提交的实际,所以kafka还提供了手动提交offset的api
手动提交分为两种,分别是commitSync(同步提交)和commitAsync(异步提交)
相同点是,都可以将本次提交的一批数据最高的偏移量提交,
不同点是,同步提交会阻塞当前的线程,会一直等到提交成功,并且会自动失败重试
异步提交,则没有失败重复机制,所以或有提交失败的可能
指定offer消费
auto。offset。reset=earliest|latest|none 默认是latest
分别代表的意思:
earliest:自动将偏移量重置为最早的偏移量。-from-beginning
latest(默认值):自动的将偏移量重置为最新的偏移量
none:如果没有找到消费者组的先前偏移量,就向消费者抛出异常
当然也可以指定开始消费的数据位置,也可以指定时间消费
重复消费和漏消费
- 重复消费:已经消费了数据,但是offset没有提交
- 漏消费:先提交了offset后消费,有可能会造成数据的漏消费
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IkB4nuvM-1659417546723)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220727214951171.png)]
如果想要完成消费者精确的一次消费,就需要消费端将消费过程和提交offset过程做原子绑定,此时就需要将offset保存到支持事务的介质中,如mysql
数据积压
kafka中的数据每隔七天就会被清空一次,但是如果消费处理数据的速度比较慢,例如时间已经过了四天,但是只消费了实际数据的10%,此时就需要想办法提高消费者的消费速率,提高数据的吞吐量以加快数据的处理从而避免数据时间到期造成的数据丢失
首先此时的情况是,kafka的消费能力不足,可以增加topic的分区数,并且增加消费者的数据量
如果是消费者的消费能力不足,可以提高每次消费者拉取数据的数量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3KCwf2Q4-1659417546723)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220727220240659.png)]
set提交的实际,所以kafka还提供了手动提交offset的api
手动提交分为两种,分别是commitSync(同步提交)和commitAsync(异步提交)
相同点是,都可以将本次提交的一批数据最高的偏移量提交,
不同点是,同步提交会阻塞当前的线程,会一直等到提交成功,并且会自动失败重试
异步提交,则没有失败重复机制,所以或有提交失败的可能
指定offer消费
auto。offset。reset=earliest|latest|none 默认是latest
分别代表的意思:
earliest:自动将偏移量重置为最早的偏移量。-from-beginning
latest(默认值):自动的将偏移量重置为最新的偏移量
none:如果没有找到消费者组的先前偏移量,就向消费者抛出异常
当然也可以指定开始消费的数据位置,也可以指定时间消费
重复消费和漏消费
- 重复消费:已经消费了数据,但是offset没有提交
- 漏消费:先提交了offset后消费,有可能会造成数据的漏消费
[外链图片转存中…(img-IkB4nuvM-1659417546723)]
如果想要完成消费者精确的一次消费,就需要消费端将消费过程和提交offset过程做原子绑定,此时就需要将offset保存到支持事务的介质中,如mysql
数据积压
kafka中的数据每隔七天就会被清空一次,但是如果消费处理数据的速度比较慢,例如时间已经过了四天,但是只消费了实际数据的10%,此时就需要想办法提高消费者的消费速率,提高数据的吞吐量以加快数据的处理从而避免数据时间到期造成的数据丢失
首先此时的情况是,kafka的消费能力不足,可以增加topic的分区数,并且增加消费者的数据量
如果是消费者的消费能力不足,可以提高每次消费者拉取数据的数量
[外链图片转存中…(img-3KCwf2Q4-1659417546723)]