从外部重置一个运行中consumer group的消费进度
对于0.10.1以上版本的kafka, 如何从外部重置一个运行中的consumer group的进度呢?比如有一个控制台,可以主动重置任意消费组的消费进度重置到12小时之前, 而用户的程序可以保持运行状态,无需下线或重启。
需要这么几个步骤:
1. 加入这个group
2. 踢掉所有其它group memeber
3. try assign all TopicPartition to this client
4. commit offsets
5. leave group
其中第二步是为了让自己当上leader,当然有可能不需要踢掉其它所有成员就能当上leader(因为谁能当leader实际上是按hashmap的迭代次序来的)。
当上consumer group的leader以后,需要把所有partition assign给自己,这个需要一个特殊的PartitionAssignor。由于这个assignor的协议跟其它consumer group协议不同(但是也可以搞一个表面上协议相同,实际上逻辑不同的assignor),而cooridnator会阻止与当前leader使用的协议不同的成员加入,所以还是需要踢掉其它成员。
public class ExclusiveAssignor extends AbstractPartitionAssignor { public interface Callback {
void onSuccess();
} private static Logger LOGGER = LoggerFactory.getLogger(ExclusiveAssignor.class); public static String NAME = "exclusive"; private String leaderId = null;
private Callback callback = null; public void setLeaderId(String leaderId) {
this.leaderId = leaderId;
}
public void setCallBack(Callback callBack){this.callback = callBack;} @Override
public String name() {
return NAME;
} private Map<String, List<String>> consumersPerTopic(Map<String, List<String>> consumerMetadata) {
Map<String, List<String>> res = new HashMap<>();
for (Map.Entry<String, List<String>> subscriptionEntry : consumerMetadata.entrySet()) {
String consumerId = subscriptionEntry.getKey();
for (String topic : subscriptionEntry.getValue())
put(res, topic, consumerId);
}
return res;
} @Override
public Map<String, List<TopicPartition>> assign(Map<String, Integer> partitionsPerTopic,
Map<String, List<String>> subscriptions) {
LOGGER.info("perform exclusive assign");
if(leaderId == null)
throw new IllegalArgumentException("leaderId should already been set before assign is called");
if(callback == null)
throw new IllegalArgumentException("callback should already been set before assign is called"); List<TopicPartition> allPartitions = new ArrayList<TopicPartition>();
partitionsPerTopic.forEach((topic, partitionNumber) -> {
for(int i=0; i < partitionNumber; i++)
allPartitions.add(new TopicPartition(topic, i));
});
Map<String, List<TopicPartition>> assignment = new HashMap<>();
for (String memberId : subscriptions.keySet()) {
assignment.put(memberId, new ArrayList<TopicPartition>());
if(memberId.equals(leaderId)){
assignment.get(memberId).addAll(allPartitions);
}
}
callback.onSuccess();
return assignment;
} }
这个assignor需要知道leaderId是哪个,而leaderId可以在KafkaConsumer的
protected Map<String, ByteBuffer> performAssignment(String leaderId,
String assignmentStrategy,
Map<String, ByteBuffer> allSubscriptions)
中获取,所以还需要修改一下KafkaConsumer的代码,以确保这个KafkaConsumer的poll并不实际拉取消息,而只是执行commit。
驱逐其它member,可以使用AdminClient完成
def forceLeave(coordinator: Node, memberId: String, groupId: String) = {
logger.info(s"forcing group member: $memberId to leave group: $groupId ")
send(coordinator, ApiKeys.LEAVE_GROUP, new LeaveGroupRequest(groupId, memberId))
}
最终的逻辑就是
private def forceCommit(consumer: SimpleKafkaConsumer[_, _], groupId: String, topics: Seq[String], maxRetries: Int, toCommit: Map[TopicPartition, OffsetAndMetadata], coordinatorOpt: Option[Node] = None) = {
consumer.subscribe(JavaConversions.seqAsJavaList(topics))
val assignedAll = new AtomicBoolean(false)
consumer.setExclusiveAssignorCallback(new Callback {
override def onSuccess(): Unit = assignedAll.set(true)
})
var currentRetries = 0
val coordinatorNode = coordinatorOpt.getOrElse(adminClient.findCoordinator(groupId))
while (!assignedAll.get() && currentRetries < maxRetries) {
logger.info(s"trying to reset offset for $groupId, retry count $currentRetries ....")
clearCurrentMembers(coordinatorNode, groupId, Some(ConsumerGroupManager.magicConsumerId))
consumer.poll(5000)
printCurrentAssignment(consumer)
currentRetries = currentRetries + 1
}
if (currentRetries >= maxRetries)
throw new RuntimeException(s"retry exhausted when getting leadership of $groupId")
val javaOffsetToCommit = JavaConversions.mapAsJavaMap(toCommit)
consumer.commitSync(javaOffsetToCommit)
logger.info(s"successfully committed offset for $groupId: $toCommit")
consumer.unsubscribe()
}
def forceReset(offsetLookupActor: ActorRef, groupId: String, ts: Long, maxRetries: Int)(implicit executionContext: ExecutionContext): Boolean = {
logger.info(s"resetting offset for $groupId to $ts")
val groupSummary = adminClient.describeConsumerGroup(groupId)
val topics = groupSummary.subscribedTopics
if (topics.isEmpty)
throw new IllegalStateException(s"group $groupId currently subscribed no topic")
val offsetToCommit = getOffsetsBehindTs(offsetLookupActor, topics, ts, 10000)
val consumer = createConsumer(groupId)
try {
forceCommit(consumer, groupId, topics, maxRetries, offsetToCommit)
true
} finally {
consumer.close()
}
}
具体代码见 https://github.com/iBuddha/kafka-simple-ui/blob/master/app/kafka/authorization/manager/utils/ConsumerGroupManager.scala
需要注意的是,发送LeaveGroupRequest可能会使得某些成员到broker的连接断掉,发生这种情况的原因是:当一个consumer发送JoinGroupRequest以后,外部的client再发送一个LeaveGroupRequest把这个consumer踢掉,会使得它个consumer无法收到JoinGroupResponse,从而使得NetworkClient以为连接挂掉。不过client以后会重新连接。而且,在外部client踢掉其它成员并且重新commit offset的过程中,其它consumer不一定有机会加入到group中,因而可能不受这个问题的影响。
从外部重置一个运行中consumer group的消费进度的更多相关文章
- 在linux下,查看一个运行中的程序, 占用了多少内存
1. 在linux下,查看一个运行中的程序, 占用了多少内存, 一般的命令有 (1). ps aux: 其中 VSZ(或VSS)列 表示,程序占用了多少虚拟内存. RSS列 表示, 程序占用了多少物 ...
- 在linux下,怎么去查看一个运行中的程序, 到底是占用了多少内存
1. 在linux下,查看一个运行中的程序, 占用了多少内存, 一般的命令有 (1). ps aux: 其中 VSZ(或VSS)列 表示,程序占用了多少虚拟内存. RSS列 表示, 程序占用了多少物 ...
- linux下,一个运行中的程序,究竟占用了多少内存
linux下,一个运行中的程序,究竟占用了多少内存 1. 在linux下,查看一个运行中的程序, 占用了多少内存, 一般的命令有 (1). ps aux: 其中 VSZ(或VSS)列 表示,程序占用 ...
- kafka中consumer group 是什么概念?
同样是逻辑上的概念,是Kafka实现单播和广播两种消息模型的手段.同一个topic的数据,会广播给不同的group:同一个group中的worker,只有一个worker能拿到这个数据.换句话说,对于 ...
- WINDOWS中, 如何查看一个运行中的程序是64位还是32位的
转自:https://blog.csdn.net/dayday3923/article/details/78597453?locationNum=7&fps=1 方法一: 任务管理器法任务管理 ...
- linux暂停一个在运行中的进程【转】
转自:https://blog.csdn.net/Tim_phper/article/details/53536621 转载于: http://www.cszhi.com/20120328/linux ...
- Kafka consumer group位移0ffset重设
本文阐述如何使用Kafka自带的kafka-consumer-groups.sh脚本随意设置消费者组(consumer group)的位移.需要特别强调的是, 这是0.11.0.0版本提供的新功能且只 ...
- Kafka设计解析(十九)Kafka consumer group位移重设
转载自 huxihx,原文链接 Kafka consumer group位移重设 本文阐述如何使用Kafka自带的kafka-consumer-groups.sh脚本随意设置消费者组(consumer ...
- Kafka consumer group位移重设
本文阐述如何使用Kafka自带的kafka-consumer-groups.sh脚本随意设置消费者组(consumer group)的位移.需要特别强调的是, 这是0.11.0.0版本提供的新功能且只 ...
随机推荐
- Visual Studio for Mac 安装时无法连接到网络等问题
问题: 1.下载 vs for mac 离线安装包 离线下载地址https://download.microsoft.com/download/3/d/4/3d42f40f-4f0a-4613-920 ...
- vue-music 关于Player (播放器组件)--播放和进度条
迷你播放器 1.播放器组件会在各个页面的情况下会打开. 首先在vuex state.js 中定义全局的播放器状态 import {playMode} from 'common/js/config.js ...
- 堆管理之malloc和free分析
在win7 64环境下分析 1.malloc代码 int main(){ void *p = malloc(0xa8); memset(p, 'a', 0xa8); free(p); return 0 ...
- Java实现打包下载BLOB字段中的文件
概述 web项目的文件打包下载实现:servlet接收请求,spring工具类访问数据库及简化大字段内容获取,org.apache.tools.zip打包. 必要提醒:当前总结是继Java实现下载BL ...
- 【java NIO】服务器端读写图片的一次排错经历
上传文件方面: 一.前端 使用的是jQuery框架来上传图片,参考的是harttle大神博客:http://harttle.com/2016/07/04/jquery-file-upload.html ...
- Xamarin中Unsupported major.minor version 52.0问题解决
Xamarin中Unsupported major.minor version 52.0问题解决 出现这种问题,是由于所使用的Java代码使用Java 8所才具有的特性.这个时候,需要将JDK升级到J ...
- Python生成随机数的一些函数
头文件: import random 1.生成一个随机浮点数,范围是0-1: print random.random() 2.生成指定范围内的随机浮点数: print random.uniform(a ...
- 【BZOJ 1052】 1052: [HAOI2007]覆盖问题 (乱搞)
1052: [HAOI2007]覆盖问题 Description 某人在山上种了N棵小树苗.冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄 膜把这些小树遮盖起来,经过一番长久的 ...
- 【线段树】XIII Open Championship of Y.Kupala Grodno SU Grodno, Saturday, April 29, 2017 Problem J. Jedi Training
题意:给你一个序列,支持两种操作:单点修改:询问一个区间中所有相邻位置下标奇偶性均不同的子序列中,和最大的是多少. 线段树每个结点维护四个值: 以奇数下标开始到奇数下标结束的最大子序列和: 以偶数下标 ...
- 【线段树/区间开平方】BZOJ3211-花神游历各国
[题目大意] 给出一些数,有两种操作.(1)将区间内每一个数开方(2)查询每一段区间的和 [思路] 普通的线段树保留修改+开方优化.可以知道当一个数为0或1时,无论开方几次,答案仍然相同.所以设置fl ...