Kafka Java consumer动态修改topic订阅
前段时间在Kafka QQ群中有人问及此事——关于Java consumer如何动态修改topic订阅的问题。仔细一想才发现这的确是个好问题,因为如果简单地在另一个线程中直接持有consumer实例然后调用subscribe进行修改,consumer端必然会抛出异常ConcurrentModificationException:KafkaConsumer is not safe for multi-threaded access
和KafkaProducer不同的是,KafkaConsumer不是线程安全的,所以我们不能直接在没有同步保护的机制下直接启用另一个线程调用consumer的任何方法(除了wakeup)。因此,实现这个需求有两种途径:
- 使用重量级的synchorinzed机制来实现线程安全
- 借助Java类库已有的线程安全数据结构来实现
如果是第一种方式,则无论哪个线程访问consumer都必须要配备必要的同步保护机制,代价相当大且极易出错。本文选取第二种方式,我们可以借助Java提供的ConcurrentLinkedQueue来帮助我们实现。具体的步骤为:
- 构建ConcurrentLinkedQueue对象分别给两个线程使用(这里并不限定于两个线程,但这个需求最可能的实际场景是consumer主线程和一个后台管理类的用户线程,而后者负责触发“动态修改订阅”逻辑)
- 调用KafkaConsumer.poll(timeout)来不断消费消息。经常有人问这里的timeout到底是做什么用的?这里统一回答一下:这里的timeout赋予了用户在consumer读取消息后可以执行其他一些操作的能力,比如定期的记录日志等。如果你的consumer没有这样的需求,那么调用KafkaConsumer.poll(1000)和KafkaConsumer.poll(Integer.MAX)没有任何区别。事实上, 我们更加推荐用户使用KafkaConsumer.poll(Integer.MAX) + wakeup的方式来响应后端其他逻辑!
- 每次poll之后尝试去探查一下ConcurrentLinkedQueue有没有新东西(如果有说明订阅topic列表发生变化),响应之
- 使用另一个线程往ConcurrentLinkedQueue中插入新的订阅信息
完整样例代码如下:
public class ConsumerTest { public static void main(String[] args) {
final ConcurrentLinkedQueue<String> subscribedTopics = new ConcurrentLinkedQueue<>(); // 创建另一个测试线程,启动后首先暂停10秒然后变更topic订阅
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// swallow it.
}
// 变更为订阅topic: btopic, ctopic
subscribedTopics.addAll(Arrays.asList("btopic", "ctopic"));
}
};
new Thread(runnable).start(); Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "my-group1");
props.put("auto.offset.reset", "earliest");
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props); // 最开始的订阅列表:atopic、btopic
consumer.subscribe(Arrays.asList("atopic", "btopic"));
while (true) {
consumer.poll(2000); //表示每2秒consumer就有机会去轮询一下订阅状态是否需要变更
// 本例不关注消息消费,因此每次只是打印订阅结果!
System.out.println(consumer.subscription());
if (!subscribedTopics.isEmpty()) {
Iterator<String> iter = subscribedTopics.iterator();
List<String> topics = new ArrayList<>();
while (iter.hasNext()) {
topics.add(iter.next());
}
subscribedTopics.clear();
consumer.subscribe(topics); // 重新订阅topic
}
}
// 本例只是测试之用,使用了while(true),所以这里没有显式关闭consumer
// consumer.close();
}
}
输出如下:
[atopic, btopic]
[atopic, btopic]
[atopic, btopic]
[ctopic, btopic]
[ctopic, btopic]
由此可见,本consumer在没有关闭的情况下动态进行了topic的订阅变更。另外需要说一下,动态变更时最好不要直接调用subscribe(topics),而是要显式地定义ConsumerRebalanceListener以避免位移提交的混乱。
Kafka Java consumer动态修改topic订阅的更多相关文章
- [Kafka] - Kafka Java Consumer实现(一)
Kafka提供了两种Consumer API,分别是:High Level Consumer API 和 Lower Level Consumer API(Simple Consumer API) H ...
- 关于Kafka java consumer管理TCP连接的讨论
本篇是<关于Kafka producer管理TCP连接的讨论>的续篇,主要讨论Kafka java consumer是如何管理TCP连接.实际上,这两篇大部分的内容是相同的,即consum ...
- [Kafka] - Kafka Java Consumer实现(二)
Kafka提供了两种Consumer API,分别是:High Level Consumer API 和 Lower Level Consumer API(Simple Consumer API) H ...
- Java实现动态修改Jar包内文件内容
import java.io.*; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; ...
- kafka 客户端 consumer 配置参数
1.Consumer Group 与 topic 订阅 每个Consumer 进程都会划归到一个逻辑的Consumer Group中,逻辑的订阅者是Consumer Group.所以一条message ...
- kafka java动态获取topic并动态创建消费者
1.获取所有topic package com.example.demo; import java.io.IOException; import java.util.List; import org. ...
- Kafka动态增加Topic的副本
一.kafka的副本机制 由于Producer和Consumer都只会与Leader角色的分区副本相连,所以kafka需要以集群的组织形式提供主题下的消息高可用.kafka支持主备复制,所以消息具备高 ...
- CDH下集成spark2.2.0与kafka(四十一):在spark+kafka流处理程序中抛出错误java.lang.NoSuchMethodError: org.apache.kafka.clients.consumer.KafkaConsumer.subscribe(Ljava/util/Collection;)V
错误信息 19/01/15 19:36:40 WARN consumer.ConsumerConfig: The configuration max.poll.records = 1 was supp ...
- Kafka Java API获取非compacted topic总消息数
目前Kafka并没有提供直接的工具来帮助我们获取某个topic的当前总消息数,需要我们自行写程序来实现.下列代码可以实现这一功能,特此记录一下: /** * 获取某个topic的当前消息数 * Jav ...
随机推荐
- C/C++文件输入输出操作——FILE*、fstream、windowsAPI
基于C的文件操作在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之. 一.流式文件操作这种方式的文件操作有一个重要的结构FILE,FILE在头文件stdio. ...
- on SDN
sdn (software defined network ) emulex 网络 新型网络创新架构 网络虚拟化的一种实现方式 核心技术:OpenFlow 分离网络设备的控制层面和数据层面 目的:实现 ...
- 如何利用pyCharm编写和运行python文件
在安装python环境后,通常可以利用IDE pyCharm来编译我们的python文件.创建一个python文件夹,用pyCharm打开文件夹,在文件夹中新建一个python文件demo.py 也许 ...
- Linux之查看切换Shell
1.查看存在的shell cat /etc/shells 2.查看使用的shell echo $SHELL 3.切换shell 切换bash chsh -s /bin/bash 切换zsh chsh ...
- python3 实现mysql数据库连接池
首先声明一下,这篇博客进行了通过自己的代码方式,加上这篇博客,最后总结出这段代码.参考博客连接:http://blog.csdn.net/zbc1090549839/article/details/5 ...
- App Store那些事儿
5条建议优化手机游戏的苹果App Store截图 第一:遵守应用商店的规定 进入应用商店的每一款应用都要加上至少一张截图,并且尺寸大小必须符合应用商店的惯例. 第二:显示营销信息 既然你已经知道规定的 ...
- (原创)关于FFmpeg的一些有关的初始化默认值的问题
最近手头上要做一个媒体格式分析库,能解析文件,流的视频格式,编码格式等一些重要的视频参数能进行尽量多的提取.当我们做媒体相关方面的东西,自然而然就会想到FFmpeg这个强大的开源媒体库,所以我们肯定会 ...
- asp.net Core EF core ( Entity Framework 7 ) 数据库更新维护
CreateDatabaseIfNotExists等之前的API已经废弃,现在采用的是微软封装好,简化.高效的API,migrations 因为,旧API,要付出高昂的代价,以及局限性 打开VS20 ...
- 文本处理三剑客之 sed详解
1.简介 sed是非交互式的编辑器,它不会修改文件,除非使用shell重定向来保存结果.默认情况下,所有的输出行都被打印到屏幕上. sed编辑器逐行处理文件(或输入),并将结果发送到屏幕.具体过程如下 ...
- (https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000014550004)Topic: Caught java.io.CharConversionException. ERRORCODE=-4220, SQLSTATE=null
270002WDPN 3 Posts 0 people l ...