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 ...
随机推荐
- 关于go语言的环境配置 SDK+path+工作目录
第一步: 安装Golang的SDK http://golang.org,下载最新的安装包,之后双击安装即可. 安装完成之后,打开终端,输入go.或者go version(查看安装版本)出现如下信息即表 ...
- latin-1 codec cant encode characters in position 42-48: ordinal not in range256 下载文件时候报错
python后端写下载文件, 这个时候出现了这个错误 latin-1 codec cant encode characters in position 42-48: ordinal not in ra ...
- (转)tcp和udp能否发送0字节的数据包
版权声明:本文为博主原创文章,未经博主允许不得转载. 转自:http://blog.csdn.net/wzx19840423/article/details/6643094 最近去一家牛逼的公司面试 ...
- T4使用经验
.<#@ template debug="true" hostspecific="true" language="C#" #> ...
- FXAA
无抗锯齿 SSAA 硬件抗锯齿,OpenGL自带,4x FXAA 从图中可以看出 FXAA抗锯齿,没有硬件MSAA抗锯齿效果好
- Objc将数据写入iOS真机的plist文件里
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 假设认为写的不好请多提意见,假设认为不错请多多支持点赞.谢谢! hopy ;) 怎样写入模拟器的博文在 这里 可是这对真机无论用,由于在真机环 ...
- HTML5 FileReader
利用HTML5中的FileReader类,动态切换af中Panel的背景,动态设置img元素的图片 1 if(FileReader){ 2 $('.panel').on("tap" ...
- 备忘录:在alpine上安装kvm
原文: https://wiki.alpinelinux.org/wiki/KVM KVM is an open source virtualization solution in a ke ...
- jquery easyui datagrid实现单行的上移下移,以及保存移动的结果
1.实现行的上移.下移. 说明: 1.1 通过datagrid生成的表格有固定的格式,比如,表格div的class名是datagrid-view.比如每一行tr都有id和datagrid-row-in ...
- [转]油猴Tampermonkey-让百度云下载飞起来
1. 简介 Tampermonkey,油猴脚本是一款免费的浏览器扩展程序. 我们这里用于Chrome浏览器,目的是为了让百度云里面的文件以满速下载,VIP还得出钱呢. 2. 安装 安装Lantern蓝 ...