先功能刚上线,点检发现新功能居然不可用,看了kafka后台后更懵了,怎么所有的topic都掉线了???
先提几个问题
- kafka一个consumer消费超时异常,会对不其他的topic产生影响吗?
- java客户端的多个kafka消费者的消费速率,会因为在同一个consumer group 下,而产生影响吗?
- spring-kakfa,如何在不增加硬件的情况下增加consumer?
问题有了,我们倒着来一个个看
spring-kakfa,如何在不增加硬件的情况下增加consumer?
增加consumer,加设备基础操作,不过有时候我们服务的负载不高,没必要上来就是增加硬件
那就是增加消费线程了
spring-kakfa上操作就非常的方便,初始化ConcurrentKafkaListenerContainerFactory的时候setConcurrency就可以很方便的调整consumer的个数,如果不设置这个值得话,默认是1
还有其它方法调整吗?有的
这个注解应该都比较熟悉,这个上面也可以设置
那么这些设置concurrency的优先级呢
在org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory#initializeContainer这边我们可以看到
这边的endpoint是什么呢?
这个endpoint是基于@KafkaListener生成的,一一对应
所以优先级是:
注解 > factory.setConcurrency(1) > 默认值
好了,我们可以充分压榨设备的性能了~
java客户端的多个kafka消费者的消费速率,会因为在同一个consumer group 下,而产生影响吗?
先说答案:正常情况下不会
首先一台部署了kafka client 是几个consumer?1个吗
大概率不是哈
我们项目中一般使用@KafkaListener来生成consumer
一个@KafkaListener至少生成一个consumer,为什么说至少呢,因为上面我们说过的concurrency这个值啊,我们有两个地方可以调整这个值,所以n个@KafkaListener都把concurrency设置成m,那么consumer就是m*n了啊
每个consumer独占一个线程
每个consumer都会有一个Fetcher,这个Fetcher是什么呢,他是拉取Partition里面数据的直接拉手
org.apache.kafka.clients.consumer.internals.Fetcher#fetchedRecords
这个方法将基于Partition拉取到每个Partition里面的数据
具体实现如下
循环拉取maxPollRecords条消息,当拉到maxPollRecords个数的消息或者查询Partition里面没有数据的话就推出循环
这个maxPollRecords是什么呢?
其实这个是可以我们配置的
对应的是max.poll.records 这个参数
所以当我们把max.poll.records设置成400那我们消费到的数据可能是一个Partition里面的数据,也可能是多个Partition里面的数据加起来的
kafka一个consumer消费超时异常,会对不其他的topic产生影响吗?
消费超时是怎么产生的呢
这边涉及两组参数
第一组
session.timout.ms超时时间是多少和heartbeat.interval.ms控制发送心跳的频率
服务端session.timout.ms时间内没有 收到客户的心跳请求,就超时
第二组
max.poll.records(拉取的个数)和max.poll.interval.ms(拉取的间隔时间)
我们都知道消费者poll数据后,需要一些处理,再进行拉取。如果两次拉取时间间隔超过这个参数设置的值,那么消费者就会被踢出消费者组。也就是说,拉取,然后处理,这个处理的时间不能超过max.poll.interval.ms这个参数的值。
那么消费超时之后,会发生什么呢----重平衡(Rebalance)
我们看下重平衡的触发条件主要的三个条件:
- 消费者组内成员发生变更,这个变更包括了增加和减少消费者。注意这里的减少有很大的可能是被动的,就是某个消费者崩溃退出了
- 主题的分区数发生变更,kafka目前只支持增加分区,当增加的时候就会触发重平衡
- 订阅的主题发生变化,当消费者组使用正则表达式订阅主题,而恰好又新建了对应的主题,就会触发重平衡
一个consumer消费超时异常,导致了Consumer group进行了重平衡
这时候要讲重平衡的3种策略了吗?
range,roundrobin,sticky
不展开,参考文章里面有详细说,直接说结论
range,roundrobin会 “stop-the-world”再平衡
默认的(range)再平衡方法存在一个缺点。每个消费者都需要放弃之前已经分配的主题分区,并且直到重新分配主题分区之后才进行数据处理,这个再平衡有时被称为“stop-the-world”再平衡
sticky为了避免不必要的主题平衡而出现的
不过目前查到的资料上有写这个策略实现复杂,提出也较晚,可能有bug,使用的也不多 - -!
想体验的话可以设置一下kafka的消费端参数
partition.assignment.strategy=org.apache.kafka.clients.consumer.StickyAssignor
结论
分情况
- 对没有使用相同消费组的topic肯定是没有影响的
- 对使用了相同消费组的topic是有影响的
尽管在数据的拉取上来说各个consumer都是独自的线程,不应该影响数据拉取和处理速度
,但是使用了相同的消费组
,一个consumer 超时,会导致整个整个consumer group “stop-the-world”再平衡
然后超时的consumer处理完逻辑,又会再次加入consumer group ,触发再平衡
然后下线,触发再平衡
...
这样整个consumer group都会处于一个病态,但是不看消费状态,只看业务的话,只有超时的这个topic会没法完成任务,其它topic还是可以继续往后消费的(匍匐前行了属于是)
一次上线事故回顾
上面所说的重平衡就是我们kafka消费崩溃的具体原因 我们项目中大多数的topic都公用着同一个消费组,新版本上线,有一个kafka cuonumer 的数据处理逻辑做了新增,而新增的这个部分查询数据库却没有命中索引,所以导致了消费超时
然而加了索引之后有好转,但是并没有完全解决,还是有几率导致消费端集体下线
然后我们再分析上线后有一段时间消费异常,导致kafka中的数据没有被正常的消费掉,产生了数据堆积
这样,根据max.poll.records=500的设定,每次消费处理的数据量都是500个拉满,而max.poll.interval.ms设置的偏小,由于在旧的逻辑上加了多次的调用下游服务的操作,导致了原来的这两个参数的配合达到了一个使用正常的临界值的状态,所以消费端的消费状态还是有问题,于是我们调整了这两个数值后,重启服务,所有消费都恢复了正常的状态
参考
\