Spring boot 卡夫卡消费者动态选择话题
我在Spring Boot中配置了一个Kafka消费程序。下面是config类:Spring boot 卡夫卡消费者动态选择话题,spring-boot,configuration,kafka-consumer-api,spring-kafka,Spring Boot,Configuration,Kafka Consumer Api,Spring Kafka,我在Spring Boot中配置了一个Kafka消费程序。下面是config类: @EnableKafka @Configuration @PropertySource({"classpath:kafka.properties"}) public class KafkaConsumerConfig { @Autowired private Environment env; @Bean public ConsumerFactory<String, Gene
@EnableKafka
@Configuration
@PropertySource({"classpath:kafka.properties"})
public class KafkaConsumerConfig {
@Autowired
private Environment env;
@Bean
public ConsumerFactory<String, GenericData.Record> consumerFactory() {
dataRiverProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, env.getProperty("bootstrap.servers"));
dataRiverProps.put(ConsumerConfig.GROUP_ID_CONFIG, env.getProperty("group.id"));
dataRiverProps.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, env.getProperty("enable.auto.commit"));
dataRiverProps.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, env.getProperty("auto.commit.interval.ms"));
dataRiverProps.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, env.getProperty("session.timeout.ms"));
dataRiverProps.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, env.getProperty("auto.offset.reset"));
dataRiverProps.put(KafkaAvroDeserializerConfig.SCHEMA_REGISTRY_URL_CONFIG, env.getProperty("schema.registry.url"));
dataRiverProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, KafkaAvroDeserializer.class.getName());
dataRiverProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, KafkaAvroDeserializer.class.getName());
return new DefaultKafkaConsumerFactory<>(dataRiverProps);
}
@Bean
public ConcurrentKafkaListenerContainerFactory<String, GenericData.Record> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, GenericData.Record> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
return factory;
}
}
请注意,我正在使用topics=“#{${kafka.topics}.split(',')}”从属性文件中提取主题。
这就是我的kafka.properties文件的外观:
kafka.topics=pwdChange,pwdCreation
bootstrap.servers=aaa.bbb.com:37900
group.id=pwdManagement
enable.auto.commit=true
auto.commit.interval.ms=1000
session.timeout.ms=30000
schema.registry.url=http://aaa.bbb.com:37800
现在,如果我要向订阅添加一个新主题,比如pwdExpire,并按如下方式修改道具文件:
kafka.topics=pwdChange,pwdCreation,pwdExpire
我的消费者是否有办法在不重新启动服务器的情况下开始订阅此新主题?
我找到了这篇文章,但文档中有关于元数据.max.age.ms的内容:
强制刷新的时间段(毫秒)
元数据,即使我们没有看到任何分区领导权的变化
主动发现任何新的代理或分区
在我看来,这是行不通的。谢谢你的帮助 No;唯一的方法是使用主题模式;随着新主题的添加(与模式匹配),代理将在默认情况下在5分钟后将它们添加到订阅中 但是,您可以在运行时为新主题添加新的侦听器容器 另一个选项是在子应用程序上下文中加载
@KafkaListener
bean,并在每次主题更改时重新创建上下文
编辑
请参阅javadocs以了解KafkaConsumer.subscribe(模式)
/**
* Subscribe to all topics matching specified pattern to get dynamically assigned partitions.
* The pattern matching will be done periodically against topics existing at the time of check.
* <p>
...
/**
*订阅与指定模式匹配的所有主题以获得动态分配的分区。
*模式匹配将根据检查时存在的主题定期进行。
*
...
更多信息:我有一个计划任务,每5分钟运行一次以检查数据库。因此,如果我们在数据库中添加一些控制值,有没有办法强制程序从属性文件中提取并相应地再次使用?谢谢您可以查看SpringCloud配置并使用注释@refreshscope。我不确定这是否适用于配置注释类。因此,基本上你可以将spring config@refresh和这个链接结合起来,为生产者和消费者工厂重新初始化spring bean,这可能对你有用。我认为刷新范围在这里不起作用;AFAIK,刷新范围仅适用于被动bean;侦听器容器是一个活动组件(实现SmartLifecycle
,并由应用程序上下文启动/停止。我没有在spring cloud上运行该应用程序。谢谢!我也可以参考一些示例吗?@GaryRussell您介意添加一个模式匹配的示例吗。另外,我想澄清一下,只要我t匹配消费者正在寻找的模式,然后每5分钟提取一次。这5分钟计时器是消费者工厂默认设置的可配置属性。@Matt请参阅@KafkaListener
上的topicPattern
属性;对于所有以pwd开头的主题,它是一个正则表达式,例如pwd.
de>。5分钟是默认的metadata.max.age.ms
,这是消费者的财产(请参阅卡夫卡文档).这段时间(以毫秒为单位),在这段时间之后,即使我们没有看到任何分区领导层的变化,我们也会强制刷新元数据以主动发现任何新的代理或分区。
@Hua哪个选项的示例?@GaryRussell感谢您的回复!谢谢@GaryRussell我对选项1感兴趣。刚刚检查了Kafka的APIListener,老实说,我看不出“topics”和“topicPattern”之间有什么区别。对于“topics”--此侦听器的主题。条目可以是“topic name”、“property placeholder key”或“expressions”。表达式必须解析为主题名称。对于“topicPattern”--此侦听器的主题模式。条目可以是“主题名称”、“属性占位符键”或“表达式”。表达式必须解析为主题模式。
/**
* Subscribe to all topics matching specified pattern to get dynamically assigned partitions.
* The pattern matching will be done periodically against topics existing at the time of check.
* <p>
...