一 参数分析
这里就涉及到的问题是,消费者在创建时会有一个属性max.poll.interval.ms,该属性意思为kafka消费者在每一轮poll()调用之间的最大延迟,消费者在获取更多记录之前可以空闲的时间量的上限。如果此超时时间期满之前poll()没有被再次调用,则消费者被视为失败,并且分组将重新平衡,以便将分区重新分配给别的成员。
循环调用poll拉取broker中的最新消息。每次拉取后,会有一段处理时长,处理完成后,会进行下一轮poll。引入该配置的用途是,限制两次poll之间的间隔,消息处理逻辑太重,每一条消息处理时间较长,
但是在这次poll()到下一轮poll()时间不能超过该配置间隔,协调器会明确地让使用者离开组,并触发新一轮的再平衡。
二 问题分析与解决
首先,设置了自动提交。
尽管这不是生产建议配置,但我们还是这么做了。项目运行半年多,没出现什么问题。直到这次业务逻辑更改…
“enable.auto.commit”, true
有这两个参数,与业务处理紧密相关,更改业务逻辑之前,这两个参数分别是
max.poll.records:1000
“max.poll.interval.ms”,300000
300秒处理1000条数据插入,数据已存在直接跳过。
近期,项目业务逻辑更改,先用id查数据库,如果数据已存在,更新。如果不存在,插入。
更改业务逻辑后,消费者出现重复消费情况。经过排查,发现业务更逻辑改后,原来设置的参数不能满足消费者需求。
随后出现重复消费问题。加上时间戳,发现是业务处理时间过长。300秒处理不完业务逻辑(由于业务逻辑复杂,业务处理10条消息,耗时在30s到150s)
随后更改max.poll.records:20,重复消费偶尔出现,
随后更改max.poll.records:15,重复消费偶尔出现,
而后更改max.poll.records:10,重复消费不在出现。
更改参数后,kafka没有消息堆积,也不出现重复消费。参数更改告一段落。
三 总结
max.poll.interval.ms
主要涉及对此参数的理解,消费者两次poll()之间的最大时间间隔。所以一次poll()的处理时间要小于这个时间。
四 附上消费者参数配置
@Configuration
@EnableKafka
public class KafkaConsumerConfig {
@Value("${kafka.bootstrap-servers:ip1:9092,ip2:9092,ip3:9092}")
private String connectionPath;
@Value("${kafka.consumer.group-id:consumer-group-1}")
private String groupId;
@Value("${zookeeper.session.timeout.ms:30000}")
private String zookeeperSessionTimeOut;
@Value("${zookeeper.sync.time.ms:200}")
private String zookeeperSyncTime;
@Value("${kafka.consumer.auto-commit-interval:5000}")
private String autoCommitIntervalTime;
@Value("${max.poll.records:10}")
private int timeSection;
// @Value("${kafka.consumer.auto-offset-reset:latest}")
@Value("${kafka.consumer.auto-offset-reset:earliest}")
private String autoOffSetCommit;
@Bean
public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<String, String>> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
factory.setConcurrency(3);
factory.getContainerProperties().setPollTimeout(3000);
factory.setBatchListener(true);
return factory;
}
@Bean
public ConsumerFactory<String, String> consumerFactory() {
return new DefaultKafkaConsumerFactory<>(consumerConfigs());
}
@Bean
public Map<String, Object> consumerConfigs() {
Map<String, Object> propsMap = new HashMap<String, Object>();
// 配置要连接的zookeeper地址与端口
propsMap.put("bootstrap.servers", connectionPath);
// 配置zookeeper的组id
propsMap.put("group.id", groupId);
// zookeeper session 失效时间
propsMap.put("zookeeper.session.timeout.ms", zookeeperSessionTimeOut); //
// 配置zookeeper连接超时间隔
propsMap.put("zookeeper.sync.time.ms", zookeeperSyncTime);
// 自动提交位移变量时间间隔
propsMap.put("auto.commit.interval.ms",autoCommitIntervalTime);
// 设置拉取时间间隔
propsMap.put("max.poll.interval.ms",300000);
propsMap.put("max.poll.records", timeSection);// 每一批数量
propsMap.put("auto.offset.reset", autoOffSetCommit);
propsMap.put("enable.auto.commit", true);
propsMap.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
propsMap.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
return propsMap;
}
}
本文详细分析了Kafka消费者参数`max.poll.interval.ms`,解释了其作用及可能导致的问题。在业务逻辑更改后,消费者出现重复消费,通过调整`max.poll.records`参数从1000逐步减小至10,解决了重复消费问题,同时避免了消息堆积。总结强调理解参数对消费者行为的重要性。
1506

被折叠的 条评论
为什么被折叠?



