kafka学习系列:根据数据库获取主题列表,并根据主题启动不同的消费者,实现主题间消费互不影响
场景
公司自研框架开发中,使用了kafka组件,需要根据不同的业务,监听不同的主题。每个业务的主题是动态可变的,所以监听的主题也是需要根据变化动态地重启。
环境
| 软件 | 版本 |
|---|---|
| JDK | 8 |
| Kafka | 2.0.1 |
| spring-boot | 2.1.8.RELEASE |
| Centos | 7 |
正文
项目是基于spring-cloud而搭建的微服务框架,所以我们这边直接引用了spring-kafka项目来进行快速上手使用kafka。
一、项目依赖
项目依赖如下:
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<scope>test</scope>
</dependency>
二、项目配置
spring.kafka.consumer.group-id=test
spring.kafka.bootstrap-servers=test01:9092,test02:9092,test03:9092
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.listener.ack-mode=manual_immediate
spring.kafka.consumer.enable-auto-commit=false
spring.kafka.consumer.max-poll-records=50
三、正文
原本是使用KafkaListener来进行主题的监听,原本里面的topicPattern是可以实现动态的监听,但是设置的主题名称就得有了固定的模式了。另外,这里是有多个模块功能,而模块功能是不确定的,是动态新增的,并且需要各自消费自己的主题,不能相互影响。所以这个时候,只使用KafkaListener就稍显不足了,也没办法新增一个模块功能,就新增一个KafkaListener的方法。所以,研究了spring-kafka之后,使用了ConcurrentMessageListenerContainer来进行动态的新建及启动。具体核心的代码,请看下面:
/**
* 生成对应采集实例的主题监听容器
* @param itemId 模块ID
* @param sItemName 模块名称
* @param topics 对应的主题
* @return 容器
*/
public ConcurrentMessageListenerContainer<Integer, String> createContainer(String itemId,String sItemName,List<String> topics) {
String[] topicArray = topics.toArray(new String[topics.size()]);
boolean isNew = true;
if (containerMap.containsKey(itemId)) {
String[] oldTopics = containerMap.get(itemId).getContainerProperties().getTopics();
Boolean isDifferent = compareTwoList(oldTopics, topicArray);
if (isDifferent) {
log.info("itemID({}) 监听主题有所变动,当前监听主题为:{},变动后的主题为:{},准备重启", itemId, String.join(",", oldTopics), String.join(",", topicArray));
isNew = true;
}else{
isNew = false;
}
}
if (isNew) {
if (containerMap.containsKey(itemId)) {
containerMap.get(itemId).stop();
}
}
ContainerProperties containerProps = new ContainerProperties(topicArray);
int concurrency = Integer.parseInt(SysConfigUtil.getProperty("spring.kafka.listener.concurrency", "3"));
log.info("主题 {} 的消费并行度设置为{}",String.join(",",topicArray),concurrency);
// 绑定处理
containerProps.setMessageListener((AcknowledgingMessageListener<Integer, String>) (message, ack) -> {
log.info("消费:{}",message);
// 提交偏移量
ack.acknowledge();
});
// 设置提交状态
containerProps.setAckMode(ContainerProperties.AckMode.MANUAL_IMMEDIATE);
// 生成实例
ConcurrentMessageListenerContainer<Integer, String> container =
new ConcurrentMessageListenerContainer<>(consumerFactory, containerProps);
// 设置并行度
container.setConcurrency(concurrency);
// 设置应用名称
container.setBeanName(sItemName);
// 启动实例
container.start();
return container;
}
参考链接
总结
通过研究spring-kafka的文档和源码,最后实现了这个功能。
随缘求赞
如果我的文章对大家产生了帮忙,可以在文章底部点个赞或者收藏;
如果有好的讨论,可以留言;
如果想继续查看我以后的文章,可以左上角点击关注

浙公网安备 33010602011771号