一,问题描述:
搭建本地kafka环境,默认端口为9092
server.properties中默认配置为:
# advertised.listeners=PLAINTEXT://10.13.84.109:9092
消费者Demo程序如下:
while (true) {
if(consumer != null)
{
// timeout 阻塞时间,从kafka中取出100毫秒的数据,有可能一次取出0到N条
List
在创建consumer对象端口为9093后,进入consumer.poll(100)是发生堵塞,线程直接卡在poll中,设定的100ms的超时也无效。
private void handlerConsumer(String kafkaIp, String kafkaPort) {
Properties props = new Properties();
props.setProperty("bootstrap.servers", kafkaIp + ":" + kafkaPort);
// key反序列化
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
// value反序列化
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
// 每个消费者都必须属于某一个消费组,所以必须指定group.id
props.put("group.id", "test");
// 构造消费者对象
deviceNoifyThreadExecutor.execute(()->{
KafkaConsumer<String, String> consumerObj = null;
// 指定多主题:
List<String> topics = CbdmOptUtil.stringToStringList(PropertiesUtil.getProperty("kafka.subscribe.topics"), ConstParamErrorCode.DEFAULT_SPLIT_KEY, false);
try {
consumerObj = new KafkaConsumer<>(props);
if(consumerObj != null) {
consumerObj.subscribe(topics);
resourceNotifyConsumer.setConsumer(consumerObj);
KafkaLinkCache.DEVICE_CONSUMER_MAP.put("kafkaComsumer", consumerObj);
resourceNotifyConsumer.onMessage();
}
} catch(Exception e) {
LogUtils.logError(RunTimeLogUtil.toErrorLog(ConstParamErrorCode.SYSTEM_CODE_FAIL + "", LogObjectTypeEnum.SYSTEM,"consume",
"resolve data platform notify error"),e);
}finally {
// 关闭
consumerObj.close();
}
});
//保存配置
KafkaLinkCache.kafkaConfigCache = kafkaIp + "_" + kafkaPort;
}
二,问题原因:
在poll(0)中consumer会一直阻塞直到它成功获取了所需的元数据信息,之后它才会发起fetch请求去获取数据。虽然poll可以指定超时时间,但这个超时时间只适用于后面的消息获取,前面更新元数据信息不计入这个超时时间。所以,设定的timout时间失效。poll(0)这种设计的一个问题在于如果远端的broker不可用了, 那么consumer程序会被无限阻塞下去。用户指定了超时时间但却被无限阻塞,显然这样的设计时有欠缺的。特别是对于Kafka Streams而言,这个设计可能导致的问题在于Stream Thread无法正常关闭。目前源代码中依然有一些无限阻塞的场景,比如之前处理的initTransaction,commitTransaction和abortTransaction也是无限等待。
三,问题解决:
poll(Duration)这个版本修改了这样的设计,会把元数据获取也计入整个超时时间,从而避免了无效等待。
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));