一篇文章带你弄懂Kafka基本原理

目录

一、Kafka介绍

1、Kafka的定义

2、消息队列应用场景

3、Kafka结构

4、zk和Kafka

二、Kafka生产者

1、基本原理介绍

2、Kafka的异步发送

3、生产者分区原理

4、提高生产者吞吐,发送能力

5、生产者数据可靠性

6、生产者数据去重

7、消息有序

8、数据乱序

三、Kafka的broker

1、kafka的borker和zk的关系

2、broker总体流程

3、Kafka的副本

4、分区副本分配

5、手动调整分区

6、leader partition自动平衡

7、kafka文件存储(重要)

8、文件清除策略

9、Kafka如何保证高效读写

三、Kafka消费者

1、Kafka的消费方式

2、消费者组

3、消费者组初始化流程

4、消费者组消费流程

5、消费者消费分区分配和再平衡

6、offset维护位置

7、自动提交offset

8、制定offset来消费

9、重复消费和漏消费

10、数据积压

10、Kafka的Kraft模式(需要补充)


一、Kafka介绍

1、Kafka的定义

老定义:分布式的基于发布/订阅的消息队列,主要用于大数据实时处理,发布的消息分为不同的类别,订阅者只接收感兴趣的消息。

新定义:Kafka是一个开源的分布式事件流平台,高性能数据管道、流分析、数据集成和关键任务应用。

2、消息队列应用场景

缓冲消峰、解耦

3、Kafka结构

Kafka是分主题topic的,一个topic又分为多个broker,broker中有多个partition

一个partition的数据只能有一个消费者来消费,为了防止一个partition数据可能会丢失的风险,他也有partition副本的概念,每个partition分为leader和follower,生产和消费只会针对leader来进行0,follower只是负责数据同步的,只有leader挂掉之后,follower有机会变成leader。partition的leader和follower是不会存在同一个broker中的(为了防止一个borker宕机都丢失)

broke中的partition是只能增加不能减少的,因为消费者消费进度可能是不同的。

4、zk和Kafka

2.8以前必须要用zk搭配使用,zk负责记录整个集群中哪些broke运行的状态,上下线信息,也会记录leader相关信息,帮助选主。

2.8之后还可以karaft模式,随着kafka的不断发展,zk已经成为他的性能瓶颈。

二、Kafka生产者

1、基本原理介绍

首先producer调用send方法到Interceptors拦截器,然后到序列化器,partitioner分区器,然后分配到对应的队列里面,整个这些操作都是在内存里面完成的,每个分区在内存中都会对应一个队列方便管理,总内存的大小默认是32m,没一批次的大小是16k。

然后有个专门的sender线程去读取缓冲队列中的消息然后发送到集群,每批次的数据满了16k之后才会开始拉取数据,或者达到了一定的毫秒数,也会拉取(批次大小达到16k或达到时间)默认是0毫秒,也就是缓冲大小没用了,来一条就发一条,没有延迟,也可以自己设置时间。

拉取是以节点的方式来拉取的,每个内存队列都是一个节点,以这个为key,然后value是数据,发送到对应的broker,然后根据参数来看是直接返回ack还是leader收到返回还是全部接受才返回。

拉取发送的时候是允许还没有应答继续发的,比如现场拉去队列1到broker1,他前面那个没ack还是可以发送后面的,但是最多只有5个,直到有应答了才能发,最多缓冲5个;应答级别0表示生产者发送数据,不需要数据落盘应答,1leader收到后应答,-1 all要leader和isr队列所有节点收集后才应答。

2、Kafka的异步发送

只要把消息放到内存队列就代表有了,后期都是由sender线程异步去拉取不需要等kafka集群ack

有带回调的异步发送,发送完成之后可以给我们返回:主题、分区等信息,发到缓存队列里面,缓存队列返回的。

同步发送:需要发送到队列之后,等待sender发送到kafka集群,然后返回ack就清楚队列才能发送下一批,如果没有发送到kafka还需要重试,所以效率很低。在异步方法调用后加个get就是同步了。

3、生产者分区原理

发送先走拦截器,序列化器,然后分区器,然后就会到队列了。分区器可以合理使用存储资源,把每个pratition在一个broker上存储,把海量数据切割成一块块存储到多个broker上,合理的分区可以实现负载均衡。可以提高并行度,以分区为单位发送数据,消费者可以以分区为单位进行消费数据。

默认是defaultParttioner分区器,如果你指定了分区规则就用自己的,如果没有就会根据patition的数量根据key的hash去映射。如果没有partition也没有key值,那就粘性分区发往一个满了再建

4、提高生产者吞吐,发送能力

  1. 批量发送:默认的应答级别为0表示来一个在队列就拉取一个,这样效率很低,我们可以设置批次大小,然后时间修改了,等批次大小满了再发也可以
  2. 异步发送
  3. 分区并行
  4. 压缩消息

5、生产者数据可靠性

应答模式acks是0,这种就是不需要等数据落盘,应答直接继续发,这种是最不可靠的,生产环境一般不用。

1为leader落盘后就可以ack,这种是比较推荐的可靠性还可以,用于传输普通日志,允许丢失个别数据。

-1就是全部都要收到才行,主从都要同步完成才可以ack,但是效率低,一般只用于传输重要钱相关数据

但是-1也可能有数据重复问题,比如leader收到同步完给follower了,这个时候准备返回ack挂了,因为没收到ack新主又会收到消息。

6、生产者数据去重

至少一次:ack等于-1,保证数据不丢失

最多一次:ack等于0,不需要ack应答有点像udp了

精确一次:幂等性事务,不管发送到broker多少个一样的数据,broker只会持久化一条,只要pid、parttion、seqNumber相等就认为是一条消息,只会持久化一次,pid是kafka每次重启一次就会生成新id,一旦挂掉就不能通过这个判断,所以他只能保证单次会话幂等,seq是单调递增的。所以他这个幂等只能保证单分区单会话内不重复。

开启事务,必须得开启幂等性,事务协调器来处理,每个borker都会有专门的事务协调器,事务的划分是根据事务id的,然后通过事务id进行hash来知道是哪个分区,该分区leader所在的broker的那个事务协调器就是用的协调器。生产者在使用事务钱必须指定事务id先,客户端挂了也能继续处理未完成的事务。

7、消有序

生产者是发送到多个分区的,消息只能是单分区内有序,如果消费者同时消费多个分区,是不能保证有序的,但是可以通过全部拉取过来再排序,但是这样需要等数据都到齐后再消费,效率可能还不如消费单分区。

8、数据乱序

生产者在发送的时候是有5个ack缓存的,就是12345全部成功才可以6,但是12没成功可以34,所以可能34先到12才到,就是乱序的了,这种怎么办呢,可以让缓存队列的缓存设置为1,这样就保证一定是有序的,每次ack才能发下一个

但是在kafka1.x启用幂等性后,kafka服务端会缓存producer发来的最近5个元数据,无论如何都能保证最近5个有序,因为他幂等也是要看是否和之前一样所以会缓存一些。

三、Kafka的broker

1、kafka的borker和zk的关系

Zk存了kafka哪些信息:有哪些服务器,记录每个分区谁是leader,有哪些服务器可用

还会存放消费者信息,保存消费者消费到哪里了,但是要频繁更新比较慢,0.9版本后就放到kafka自己存了。还会存放辅助选举注册权,谁先抢到这个注册权,谁就当新主。

2、broker总体流程

每个borker启动都会像zk注册,启动3台,zk就会有3个节点,然后谁先把自己controller写到zk谁就是主节点,其他从节点的controller会主动跟zk拉取信息,如果主挂了他们可以随时上位。选leader的时候是在存活的里面按照启动的时候固定顺序排在前面的优先。然后生产者会往leader发送信息,follower去同步,底层采用segment1个g一个g的存储,有index索引文件来加快查询,

3、Kafka的副本

分区副本提高可靠性,默认是1个副本,生产环境一般配置两个,太多副本会增加磁盘存储空间,增加网络上数据传输,降低效率

副本分为leader和follower,生产者只会发送leader,follower找leader同步

当有人先注册到Zk,那么那个分区就是leader,其余分区去zk拉取信息,当zk监控到leader挂了,就会根据按照启动的时候固定顺序排在前面的优先,由他成为新主。

如果从挂了,会先从isr队列里面踢除,然后其他的主从继续接受同步,当挂的从恢复了,会先同步之前共同的达到最低节点offer就可以重新加入队列

主挂了,从队列踢出,会有新的主,但是新主可能没有同步完全,可能会少数据,然后其他从跟他看齐,也就是可能存在数据丢失,只能保证数据一致,不能保证丢失

4、分区副本分配

他会把不同partition的leader尽可能分开存到不同的broker,尽可能保证复杂均衡,比如有3台机器,9个leader那么就会3个3这样的

5、手动调整分区

Kafka自己是按照机器数量去分配的,但是实际上可能有些机器32t有些4t,所以有时候需要我们人为手动去进行分配。

6、leader partition自动平衡

正常情况下kafka会自动把leader partition均匀分散在各个机器上,保证读写吞吐均匀,但是如果某些broker故障,会导致leader partition过于集中在其他少部分几台broker上,这会导致少数几台broker读写请求压力过高,造成集群负载不均衡

Kafka提供了自动平衡,由参数配置默认true,有个参数可以调节超过不平衡比例就会出发broker平衡,默认10%,还有个参数配置检测不平衡率时间,默认300秒。

他是怎么算不平衡率呢?他会判断本来应该是哪个当主节点,发现broker中有的本来应该是当主但是不是,最后看多少个不满足/总的分区数就是不平衡率。

7、kafka文件存储(重要)

Topic是逻辑概念,分区是物理概念,每个partition都会对应一个log文件,log也是逻辑概念,在log里面具体数据是存在一个个segment里(1segment是1g,由log日志文件,index偏移量索引文件,timeindex时间戳索引文件(用来删除的)组成)partition生产的数据会不断追加到log文件末尾,这也算其中高效读写的原因之一。

Index为稀疏索引,每往log文件写入4kb数据,会忘index文件写入一条索引,有参数可以配置

8、文件清除策略

Kafka默认日志保存7天,可以通过参数修改,默认是7天删除,检测周期5min,日志清楚策略有delete和compact两种

  1. delete日志删除:以segment所有记录的最大时间戳作文segment的时间戳来删除,比如一个segment有很多条日志,取他最新的如果超过7天,删除整个segment,没有就不删。还有个默认关闭的配置,就是超过总大小就淘汰最早的segment,生产环境一般不会打开
  2. compact压缩策略:有点像aof按照,就是相同的key只留最新的那个,这样offer压缩后就可能是不连续的,中间可能少了,这种策略只适用特殊场景,比如消息key为用户id,value为他的资料,他更新了旧的就没用了。

9、Kafka如何保证高效读写

Kafka本身是分布式集群可以用分区技术提高并行,读数据采用稀疏索引可以快速定位要消费数据,写数据是采用顺序的追加的方式,这样说很快的

零缓存+零拷贝:Kafka的数据加工处理给kafka生产者和消费者处理,broker应用层不关心存储数据,索引不用走应用层,传输效率高。他要发给消费者得走网卡,通过网卡给消费者。pageCache页缓存:kafka重度依赖底层操作系统提供的pagecache,当上层有写数据时,操作系统只是将数据写入pagecache,当读操作时,先从pagecache查找,如果找不到再走磁盘。如果找到数据是直接给网卡的,不再经过应用层,这种就是零拷贝。他不关心数据,所有拦截器序列化什么都交给生产者和消费者了,kafka中间什么都不做。

三、Kafka消费者

1、Kafka的消费方式

消息队列消费者有推送和拉取两种方式,Kafka采用主动拉取的方式,因为每个人的消费速度都不一样,主动拉取可以更好兼容不同消费速度都消费者,缺点是如果kafka没有数据,消费者会一直循环返回空。独立的消费者可以消费一个或者多个分区,但是每个分区只能由消费者组中一个消费者消费。offset来标识消费到哪里了,所有的offset都会存到对应的topic里,老版本放到zk的,但是消费者都要和zk通信获取offset这样交互太频繁了所以直接放到topic了。

2、消费者组

组内每个消费者消费不同分区,一个分区只能有一个消费者消费,消费者组之间不影响。

3、消费者组初始化流程

Coordinator辅助实现消费者组的初始化和分区分配,每个broker都有coordinator,Coordinator选择是按照hashcode对50取%拿到的,然后所有消费者都会去Coordinator注册,然后coordinate会随机选出一个消费者作为leader,会把信息都同步给他,让他制定消费计划发给coordinator,coordinator广播给组内所有消费者,后续都按照这个计划消费,然后有心跳机制去保活,默认3秒发送一次保活机制,一旦超过45秒没消费,就会被移除,并触发平衡,或者处理时间过长5分钟,也触发再平衡。

4、消费者组消费流程

首先会初始化,消费者组向消费者网络客户端发送sendFetches,确定每次抓取大小,默认1字节,如果调大了没到并不会抓取,还有个条件是超时时间如果超过这个时间也会抓取,前面两个条件满足一个就可以拉取,还有个参数是每次最大抓取大小默认50m。接着就由消费者网络客户端向kafka集群发送send,主动拉取消息,集群会通过回调方法发消息发到消息队列里,消费者会取消息队列拉取,他拉取完会先过反序列化器,然后拦截器,再处理数据。

5、消费者消费分区分配和再平衡

到底哪个消费者消费哪个分区,怎么分配?

kafka提供四种分配策略:range、roundRobin、sticky、cooperativeSticky

默认采用的是range+cooperativeSticky,可以同时使用多个叠加

  1. range:他首先会对topic的分区变化,然后对消费者组的消费者也编号,然后分区除消费者得到每个消费者消费多少个,多出来的都给第一个。这样有个缺点,当很多topic的时候,他们所有多出来的分区都会给第一个消费者,这样会造成数据倾斜。
  2. roundRobin:针对所有的topic,他会把所有topic和分区还有消费者都放一起排好序,然后根据hashcode来进行分配
  3. sticky粘性分区:首先会尽量均匀放置分区到消费者上,在原本消费者出现问题,尽量保持原有分配到分区不变化

6、offset维护位置

生产者发送消息到leader分区,然后消费者会消费,消费了多少有个offset来标识,offset0.9后存在kafka的topic上的,0.9之前存在zk,他存储是根据key value存储的,key为groupid+topic+分区号,value为offset,每一段时间会compact,只保留最新的key

7、自动提交offset

默认自动提交,自动提交间隔默认5s,这些都可以配置,生产者和消费者就是发和拉,然后每隔5s消费者还会去kafak提交一下offset消费到哪里,分同步提交和异步提交,同步提交必须等待offset提交完毕再去消费下一批数据,异步提交offset请求后就可以消费下一批,同步会阻塞当前线程,异步没有失败重试机制,默认的自动提交是异步的。

8、制定offset来消费

消费方式有3种,earliest、latest、none。默认是latest。earliest自动将偏移量重置为最早的偏移量from beginning,latest默认的是自动重置到最新偏移量,none如果未找到消费者组的先前偏移量,则抛出异常。

9、重复消费和漏消费

重复消费:自动提交offset,每5s提交了一下,现在提交到3,消费者会继续消费消费到45然后挂了,但没有自动提交,就会出现重启重新从4开始消费,45就重新消费了。

漏消费:设置手动提交,当offset提交还没落盘,此时消费者刚好挂,那么offset已经提交,但数据未落盘,导致这部分数据内存中丢失,下次启动会以为已经消费了。

采用事务的方式才能精确消费,消费者采用事务,而且下游的必须是mysql和kafka这种也支持事务的才可以,前面的生产者和kafka也要用幂等和事务才行。

10、数据积压

消费太慢了,但是kafka的数据7天就会消失,超过7天未消费就被删除了

可以增加分区和消费者个数,还可以提高每批次拉取的数量

10、Kafka的Kraft模式(需要补充)

2.8后才有的,终于不需要zk来配合了,之前需要zk来配合做很多事情通信,网络开销非常厉害,那么现在就不需要了,这个模式应该是未来的趋势。

他把集群分为了broker节点用来存数据,controller节点用来选举等,机器可以又是broker又是controller,controller3个以上就行,然后也会有leader controller的概念。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ctg-kafka是基于Apache Kafka开发的一个开源的消息队列系统。它的基本原理是通过分布式消息发布和订阅机制来实现高吞吐量、可扩展性和容错性。 在ctg-kafka中,消息被发布到一个或多个主题(topic)中,并由一个或多个消费者进行订阅。生产者(producer)负责将消息发布到指定的主题,而消费者(consumer)则从主题中订阅并处理消息。消息以字节流的形式进行传输,并以分区(partition)的方式进行组织和存储。 每个分区都有一个唯一的标识符,并且可以在多个节点上进行复制以提供容错性和可用性。分区内的消息以顺序的方式进行存储,并且可以根据消息的偏移量(offset)进行读取和检索。 ctg-kafka还采用了基于日志的存储模型,即将所有的消息都追加到日志末尾,而不是直接修改已有的消息。这种设计可以提高写入的效率,并且保证了消息的顺序性和持久性。 另外,ctg-kafka还提供了一种称为消费者组(consumer group)的机制。多个消费者可以组成一个消费者组,并且每个分区只能由一个消费者组中的一个消费者进行消费。这样可以实现负载均衡和水平扩展,同时保证每个消息只会被消费一次。 总之,ctg-kafka通过分布式的消息队列机制和基于日志的存储模型,实现了高吞吐量、可扩展性和容错性。它在大规模数据处理和实时流处理等场景中得到了广泛的应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卒获有所闻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值