讲讲spring-kafka消费者模型源码解析

本文深入剖析了Spring Kafka消费者的工作流程,从启动过程、并发消费、消息提交策略到监听器类型,详细阐述了如何配置和管理消费者。重点讨论了ConcurrentMessageListenerContainer的并发数设定、消费进度提交(ACK机制)以及在不同监听器类型下的行为差异,同时也提及了消费者组成员变化和订阅Topic变化对消费的影响。
摘要由CSDN通过智能技术生成
 

1 整体流程

2 消费者启动

2.1 容器启动

2.1.1 consumer启动 

1)遍历每一个带有@KafkaListener注解的类或方法,经过一系列解析最终为其创建一个MessageListenerContainer,具体实现类为ConcurrentMessageListenerContainer

KafkaListenerEndpointRegistry#registerListenerContainer:

2)ConcurrentMessageListenerContainer创建完成之后,自动调用其start方法,start方法会根据我们在@KafkaListener中设置的topic和分片数来创建对应数量的KafkaMessageListenerContainer,并调用其start方法

KafkaListenerEndpointRegistry#start

AbstractMessageListenerContainer#start--->ConcurrentMessageListenerContainer#doStart

3)KafkaMessageListenerContainer.start()方法会创建一个ListenerConsumer,ListenerConsumer是一个Runnable接口实现类

AbstractMessageListenerContainer#start--->KafkaMessageListenerContainer#doStart

4)ListenerConsumer在构造的时候会创建一个Consumer,并分配对应的topic和partitions,然后执行一个while循环,在循环中不停的执行consumer.poll()方法拉取数据,并回调@KafkaListener对应的方法

5)提交到异步线程池,执行run方法

2.2 并发消费

spring-kafka可以创建单个消费者,而且还支持创建多个消费者:

ConcurrentMessageListenerContainer可以创建多个消费者,可以通过并发数属性来设置创建多少个消费者,ConcurrentMessageListenerContainer作用其实和部署多个消费者服务是一样的效果。支持创建两种类型消费者:消费者群组类型和独立消费者类。

关于ConcurrentMessageListenerContainer的并发数说明

这个并发数是指一个app实例创建多少个消费者。如果我们部署多个服务,比如10台服务,而分区个数时20,此时可以设置并发数是2,如果分区个数小于10,此时设置并发是1就可以了。

一个ip,对应三个consumer,一个consumer一个分片

注意:消费消息时使用多线程消费消息, 这种多线程处理可以在自己实现消费消息逻辑中自己实现。

3 消费者动作

3.1 指定分片消费

可以通过手动指定消费者固定消费哪一个分片。目前大多没有用到

3.2 消费进度提交(ACK机制)

1)这里while循环每次都判断是否auto commit,如果不是则processCommits

2)如果不是isManualImmediateAck,则每次是累加到offsets的map中

3)非TIME类型或者数据量到达即提交数量,即RECORD,BATCH

MANUAL,都走这里,或者COUNT/COUNT_TIME且数量达到

4)TIME时间到达

5)COUNT_TIME时间到达或者数量到达满足一种,前面已经处理数据量到达的情况

6)提交进度

这里会从offsets的map组装出commits,然后去提交(commitSync或者commitAsync),然后clear掉offsets

3.3 手动/自动提交

1)调用listener onmessage方法后,缓存待提交的消费记录

MANUAL MANUAL_IMMEDIATE类型的且非自动提交的,不会缓存,listener自己处理提交

2)处理缓存待提交的消费记录

run方法proceesCommit方法中,先处理缓存中的待提交记录,累加到offset中

累加到offset中后,交给后面的方法处理提交

3.4 重定位

暂时没有用到,重新定位分片的拉取偏移

4 消息拉取

spring-kafka拉取消息调用的原始的kafkaconsumer

4.1 拉取进度

consumer实例订阅的每个topic-partition都会有一个对应的TopicPartitionState对象,在这个对象中会记录上面内容,最需要关注的就是position这个属性,它表示上一次消费的位置

4.2 初始拉取偏移

1)首先查看当前TopicPartition的position是否为空,如果不为空,表示知道下次fetch position(拉取数据从哪个位置开始拉取),但是第一次消费这个TopicPartitionState.position肯定为空。

2)第一次position肯定为空,则通过各种方法,一定要获取到这个偏移。

4.3 更新拉取偏移

1)消息拉取回来后立即更新拉取偏移

不论消息是否被消费或消费正常

2)未提交消费进度的消息

除非消费者重启,或者发生重平衡,队列分给新的消费者,新消费者拉取到broker端的最近提交偏移,可以把未提交消费进度的那条消息拉取到重复消费

5 Listener类型

5.1 ACKNOWLEDGING_CONSUMER_AWARE

同时支持ACKNOWLEDGING和CONSUMER_AWARE两种类型。spring-kafka默认用这种KafkaListenerEndpoint#createMessageListenerInstance:listener endpoint的基本模型的接口,包括id,分组,主题,分区等的信息。

5.2 CONSUMER_AWARE

如果我们在消费消息时,需要用到consumer对象,则需要使用这个类型。

5.3 ACKNOWLEDGING

当需要手动提交时时,而不是自动提交或者spring-kafka自己实现提交的方式时,需要如下接口中acknowledment的acknowlegge()方法来提交偏移量

5.4 SIMPLE

就是在处理消息时,不需要考虑提交偏移量和使用Consumer对象。

5.5 决定哪种listenerType

上面说过,spring-kafka把listener封装成AcknowledgingConsumerAwareMessageListener,

所以默认用到是ACKNOWLEDGING_CONSUMER_AWARE

5.6 使用ListenerType

6 重平衡

6.1 消费端的消费者组成员变化

基本上影响最大的就是这个原因了

1)消费者处理消息超时, 即如果消费者处理消费的消息的时间超过了 Kafka集群配置的max.poll.interval.ms的值, 那么该消费者将会自动离组。

max.poll.interval.ms参数用于指定consumer两次poll的最大时间间隔(默认5分钟),如果超过了该间隔consumer client会主动向coordinator发起LeaveGroup请求,触发rebalance;然后consumer重新发送JoinGroup请求

2)心跳超时, 如果消费者在指定的session.timeout.ms时间内没有汇报心跳, 那么Kafka就会认为该消费已经dead了

3)新Consumer加入,旧consumer下线

4)重启consumer,长时间没有启动,超过心跳时间

6.2 订阅Topic变化

1)消费者订阅的topic发生变化

2)topic分区数目发生调整

6.3 JVM的影响

3)broker端所在的服务器发生GC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值