一、CPU占用过高
应用进程报CPU占用过高,且查看后台的日志解析生成速度较慢,加上日志出现重平衡分配等词,所以推测是重平衡导致CPU升高,而心跳和网络非常正常,又没有掉线或重启的应用,因此推测是poll消费时长过长导致消费被认为掉线引起重平衡。
解决方案如下:
1、调整poll消费参数:
max.poll.interval.ms: 600000
max.poll.records: 300
即一条消息平均有2秒钟的消费时长,不像默认设置的300000/500,即0.6秒要处理完一条消息,碰到部分复杂场景的数据消费时长就比较长了,平均0.6秒的消费时长风险还是比较大。
2、优化业务逻辑:调整业务逻辑,将消费逻辑简化,部分复杂场景数据后续用定时任务解决。
二、消费者异常退出
这个异常退出很诡异,只出现过一次,日志也没有异常,目前没有找到原因,估计是硬件内存等原因导致。后面紧急变更应用重启解决了。但应用重启在线上非常麻烦,因此解决方案就是消费者加上定时任务自检以及自动重启。
解决方案如下:
主体写三个类,一个是配置类,用于读取kafka消费者配置,并在启动应用时创建消费者,第二个是消费者线程类,用于将消费者传给线程启动进行轮询,第三个是编写定时任务,自检消费线程是否正常,若不正常则删除新建消费者。定时任务代码如下:
package com.longqi.bootkafka.component.job;
import cn.hutool.core.collection.CollectionUtil;
import com.longqi.bootkafka.component.KafkaConsumerRunner;
import com.longqi.bootkafka.config.KafkaConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author LongQi
* @projectName boot-integration
* @description: 消费者自检重启
* @date 2023/3/20 19:58
*/
@Slf4j
@Component
public class KafkaConsumerManageJob {
@Autowired
private KafkaConfig kafkaConfig;
@Scheduled(cron ="0 0/10 * * * ?")
public void checkConsumer(){
log.info("消费者自检...");
Map<String,Thread> threads = kafkaConfig.getConsumerThreads();
if(CollectionUtil.isEmpty(threads)){
log.error("消费者全部宕机,这里重启!");
kafkaConfig.createConsumer(null);
}else{
Integer bootNumber = 0;
for(String key:threads.keySet()){
if(threads.get(key) == null || !threads.get(key).isAlive()){
bootNumber++;
if(kafkaConfig.getConsumerRunners() !=null && kafkaConfig.getConsumerRunners().get(key) !=null){
KafkaConsumerRunner runner = kafkaConfig.getConsumerRunners().get(key);
// 停止轮询
runner.stopRun();
try {
// 注意这里睡眠时间一定要大于提交offest的时间,不然会报kafka多线程的错误
Thread.sleep(6000);
}catch (Exception e){
e.printStackTrace();
}
if(runner.getConsumer() != null){
runner.getConsumer().close();
}
kafkaConfig.getConsumerRunners().remove(key);
}
if(threads != null){
threads.remove(key);
}
}
log.error("异常消费者[{}]已删除",key);
}
kafkaConfig.createConsumer(bootNumber);
log.error("已新建{}个消费者",bootNumber);
}
log.info("消费者自检完毕");
}
}