kafka04-消费组

kafka高效读写数据的原因:

  1. kafka本身是分布式集群,多台服务器来共同处理一件事,效率高

  2. 采用分区技术存储,将海量数据切分成一块一块并行存储,同时生产者可以并行给不同的分区推送数据,消费者可以并行消费,提升效率

  3. 采用稀疏索引,可以快速定位数据,提升查找速率

  4. 以追加日志的方式顺序写入磁盘,速度快。顺序写快的原因:不需要像随机写那样需要先寻址定位,才能写入

  5. 使用了页缓存和零拷贝技术

    页缓存:kafka重度依赖底层操作系统提供的pagecache功能。当上层有写操作时,操作系统知识将数据写入pagecache。当读操作发生时,先从pagecache中查找,如果找不到,再去磁盘中读取。实际上 pagecache是把尽可能多的空闲内存都当作了磁盘存储来使用。

    零拷贝:kafka的数据加工处理操作交由生产者和消费者处理。kafka broker应用层不关心存储的数据,所以就不用走应用层,传输效率高。

*kafka消费者

kafka消费方式:

  1. pull(拉)模式(默认):消费者主动从broker中拉取数据。

  2. push(推)模式:broker主动推送给消费者

push优点:kafka知道自己什么时候有数据,有数据就推,没数据就不推。

push缺点:不知道consumer的消费能力。每个消费者的消费能力不同,可能A消费速度是10m/s, B消费速度是20m/s,C消费速度是30m/s,如果kafka以30m/s的速度推,A和B是无法承受的。

pull优点:每个consumer可能根据自己的消费能力去拉取数据

pull缺点:不知道什么kafka什么时候有数据,拉取返回的数据可能会为空

 

消费者总体工作流程:

消费者和消费者之间的独立的,可以对kafka不同的分区进行消费。

消费组 可以看成一个整体的消费者,同一分区只能由消费组中的一个消费者单独消费,否则会出现重复消费问题。

因为消费组内只能有一个消费者对一个分区进行消费,如果该消费者消费了部分数据后突然宕机了,那我们之后该如何接着之前的消费,把未消费的数据进行消费呢? offset会记录我们消费的位置 ,每个消费者的offset由消费者提交到系统主题进行保存

 

消费者组原理:

消费组是由多个groupid小童的消费者组成。

注意:在消费者api代码中必须配置消费组groupid。命令行启动消费者不填写groupid,是因为kafka会自动帮我们填写随机的groupid。

如果消费组内的消费者多于分区数,多于的消费者就处于空闲状态。

 

消费者组初始化流程:

  1. coordinator 协调者,辅助实现消费者组的初始化和分区的分配

  2. 每个broker都有一个对应的一个coordinator

  3. 每个消费者组都有自己的groupid(我们自己定义),coordinator节点选择=groupid的hashcode值%50(_consumer_offsets的分区数据)得到的值便是分区值

    例如:groupid的hashcode值=1,1%50=1,那么consumer_offsets主题的1号分区,在哪个broker上,则该broker节点的coordinator就是此次消费者组的leader。消费组下的所有消费者提交offset的时候,就往这个分区提交offset即可。

    consumer_offsets主题:未来存储消费者的offset会放在这个主题里面,该主题对应有50个分区(和存储事务的主题分区数相同)

  4. 接下来所有的消费者都会发送joinGroup请求给coordinator_leader

  5. coordinator_leader会选出一个consumer_leader

  6. coordinator_leader会把要消费topic的情况发送给consumer_leader

  7. consumer_leader会根据一种成熟的分区分配规则 制定一份计划方案,并发送给coordinator_leader

  8. coordinator_leader再把消费方案下发给各个consumer

  9. 面试经常问)每个consumer会定期和coordinator_leader保持心跳(默认3s),一旦超时(session.timeout.ms=45s),该consumer会被移除,并触发再平衡;或者消费者处理消息的时间过长(max.poll.interval.ms5分钟),也会触发再平衡

    再平衡:消费组内如果一个消费者宕机,其他活跃的消费者需要分担宕机消费者剩余的任务

  

消费者组详细消费流程:

  1. 消费者组要想工作,首先需要创建一个ConsumerNetwordClient网络连接客户端,主要用来和kafka集群交互。

  1. sendFetches,抓取数据的初始化,发送消费请求

配置参数:

  1. Fetch.min.bytes 每批次最小抓取大小,默认1字节(也就是说,如果topic-partition有1字节数据,就会进行抓取)

  2. Fetch.max.wait.ms 一批数据最小值未达到的超时时间,默认500ms(如果topic-partition内的数据没有达到minbyte抓取最小值,那么到达maxwaite,也会进行抓取)

  3. Fetch.max.bytes 每批次最大抓取大小,默认50m

  1. send方法发送请求

  2. onSuccess 回调方法,拉取到的数据会放在completedFetches 的 queue消息队列中

  3. 消费者从 completedFetches 的 queue消息队列中 拉取数据

    Max.poll.records 一次拉取数据返回信息的最大条数,默认500条

  4. 对数据进行parseRecord 反序列化 -> 拦截器 -> 处理数据

 

 

分区的分配以及再平衡:

四种主流的分区分配策略:

配置 Partition.assignment.strategy,可修改分区的分配策略。

默认策略:Range + CooperativeSticky。kafka可以使用多个分区分配策略。

  1. Range

  2. RoundRobin

  3. Sticky

  4. CooperativeSticky

Range策略:

 

RoundRobin策略:

 

Sticky分区分配策略:

粘性分区,可以解决为分配的结果带有“粘性”。即在执行一次新的分配之前,考虑上一次分配的结果,尽量减少分配的变动,可以节省大量的消耗。

分区数 / 消费者数 取余,和Range分配差不多,但不会像Range去从0开始标记,Sticky是随机的

posted @ 2022-03-09 20:01  迷路小孩  阅读(192)  评论(0)    收藏  举报