offset range 查询
offset range 查询
我们在实际使用过程中经常需要查询某个topic的某分区的offset的range
命令行:
kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list xxxx:9092 -topic xxxtopic --time -2
kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list xxxx:9092 -topic xxxtopic --time -1
-1 -2 的特殊含义:
public class ListOffsetRequest extends AbstractRequest {
public static final long EARLIEST_TIMESTAMP = -2L;
public static final long LATEST_TIMESTAMP = -1L;
}
客户端
KafkaConsumer.endOffsets(Collection)
KafkaConsumer.beginningOffsets(Collection)
Fetcher.beginningOrEndOffset(Collection, long, long)
Fetcher.retrieveOffsetsByTimes(Map<TopicPartition, Long>, long, boolean)
Fetcher.sendListOffsetRequests(boolean, Map<TopicPartition, Long>)
// Group the partitions by node.
final Map<Node, Map<TopicPartition, Long>> timestampsToSearchByNode = new HashMap<>();
for (Map.Entry<TopicPartition, Long> entry: timestampsToSearch.entrySet()) {
TopicPartition tp = entry.getKey();
PartitionInfo info = metadata.fetch().partition(tp);
if (info == null) {
metadata.add(tp.topic());
log.debug("Partition {} is unknown for fetching offset, wait for metadata refresh", tp);
return RequestFuture.staleMetadata();
} else if (info.leader() == null) {
log.debug("Leader for partition {} unavailable for fetching offset, wait for metadata refresh", tp);
return RequestFuture.leaderNotAvailable();
} else {
Node node = info.leader();
Map<TopicPartition, Long> topicData = timestampsToSearchByNode.get(node);
if (topicData == null) {
topicData = new HashMap<>();
timestampsToSearchByNode.put(node, topicData);
}
topicData.put(entry.getKey(), entry.getValue());
}
}
final RequestFuture<Map<TopicPartition, OffsetData>> listOffsetRequestsFuture = new RequestFuture<>();
final Map<TopicPartition, OffsetData> fetchedTimestampOffsets = new HashMap<>();
final AtomicInteger remainingResponses = new AtomicInteger(timestampsToSearchByNode.size());
for (Map.Entry<Node, Map<TopicPartition, Long>> entry : timestampsToSearchByNode.entrySet()) {
sendListOffsetRequest(entry.getKey(), entry.getValue(), requireTimestamps)
.addListener(new RequestFutureListener<Map<TopicPartition, OffsetData>>() {
@Override
public void onSuccess(Map<TopicPartition, OffsetData> value) {
synchronized (listOffsetRequestsFuture) {
fetchedTimestampOffsets.putAll(value);
if (remainingResponses.decrementAndGet() == 0 && !listOffsetRequestsFuture.isDone())
listOffsetRequestsFuture.complete(fetchedTimestampOffsets);
}
}
@Override
public void onFailure(RuntimeException e) {
synchronized (listOffsetRequestsFuture) {
// This may cause all the requests to be retried, but should be rare.
if (!listOffsetRequestsFuture.isDone())
listOffsetRequestsFuture.raise(e);
}
}
});
}
return listOffsetRequestsFuture;
简单点说:就是找到leader节点然后给其发送ListOffsetRequest请求。这个请求是按时间进行offset定位。
broker端
KafkaApis.handleListOffsetRequestV1AndAbove(request: RequestChannel.Request)
查询最新offset
这个值应该是在生产的时候维护好的
val lastFetchableOffset = offsetRequest.isolationLevel match {
case IsolationLevel.READ_COMMITTED => localReplica.lastStableOffset.messageOffset
case IsolationLevel.READ_UNCOMMITTED => localReplica.highWatermark.messageOffset
}
这个地方也能反映出 LEO,LSO,highwater的区别!!
查询最早offset
kafka.log.Log.fetchOffsetsByTimestamp(targetTimestamp: Long)
这个值应该是在生产的时候维护好的
@threadsafe
class Log(@volatile var dir: File,
@volatile var config: LogConfig,
@volatile var logStartOffset: Long,
@volatile var recoveryPoint: Long,
scheduler: Scheduler,
brokerTopicStats: BrokerTopicStats,
time: Time,
val maxProducerIdExpirationMs: Int,
val producerIdExpirationCheckIntervalMs: Int,
val topicPartition: TopicPartition,
val producerStateManager: ProducerStateManager,
logDirFailureChannel: LogDirFailureChannel) extends Logging with KafkaMetricsGroup {
// ......
if (targetTimestamp == ListOffsetRequest.EARLIEST_TIMESTAMP)
return Some(TimestampOffset(RecordBatch.NO_TIMESTAMP, logStartOffset))
按时间戳查询offset
先确定target segment
val targetSeg = {
// Get all the segments whose largest timestamp is smaller than target timestamp
val earlierSegs = segmentsCopy.takeWhile(_.largestTimestamp < targetTimestamp)
// We need to search the first segment whose largest timestamp is greater than the target timestamp if there is one.
if (earlierSegs.length < segmentsCopy.length)
Some(segmentsCopy(earlierSegs.length))
else
None
}
再到seg的index根据时间查找
LogSegment.findOffsetByTimestamp(timestamp: Long, startingOffset: Long)
先定位到index然后再二分查找
// LogSegment.scala
val timestampOffset = timeIndex.lookup(timestamp)
val position = index.lookup(math.max(timestampOffset.offset, startingOffset)).position
// AbstractIndex.scala
/**
* Lookup lower and upper bounds for the given target.
*/
private def indexSlotRangeFor(idx: ByteBuffer, target: Long, searchEntity: IndexSearchEntity): (Int, Int) = {
// check if the index is empty
if(_entries == 0)
return (-1, -1)
// check if the target offset is smaller than the least offset
if(compareIndexEntry(parseEntry(idx, 0), target, searchEntity) > 0)
return (-1, 0)
// binary search for the entry
var lo = 0
var hi = _entries - 1
while(lo < hi) {
val mid = ceil(hi/2.0 + lo/2.0).toInt
val found = parseEntry(idx, mid)
val compareResult = compareIndexEntry(found, target, searchEntity)
if(compareResult > 0)
hi = mid - 1
else if(compareResult < 0)
lo = mid
else
return (mid, mid)
}
(lo, if (lo == _entries - 1) -1 else lo + 1)
}
offset range 查询的更多相关文章
- 【MySQL】SQL优化系列之 in与range 查询
首先我们来说下in()这种方式的查询 在<高性能MySQL>里面提及用in这种方式可以有效的替代一定的range查询,提升查询效率,因为在一条索引里面,range字段后面的部分是不生效的. ...
- MySQL SQL优化之in与range查询【转】
本文来自:http://myrock.github.io/ 首先我们来说下in()这种方式的查询.在<高性能MySQL>里面提及用in这种方式可以有效的替代一定的range查询,提升查询效 ...
- Elasticsearch使用filter进行匹配关系and,or,not,range查询
RESTful接口URL的格式: http://localhost:9200/<index>/<type>/[<id>] 其中index.type是必须提供的. i ...
- golang LMDB入门例子——key range查询
如下,使用gomb库 package main import ( "bytes" "fmt" "io/ioutil" "os&qu ...
- 67.ORM查询条件:range的使用,使用make_aware将navie time 转换为aware time
模型的定义,models.py文件中示例代码如下: from django.db import models # 在定义模型的类时,一定要继承models.Model class Category(m ...
- 服务器文档下载zip格式 SQL Server SQL分页查询 C#过滤html标签 EF 延时加载与死锁 在JS方法中返回多个值的三种方法(转载) IEnumerable,ICollection,IList接口问题 不吹不擂,你想要的Python面试都在这里了【315+道题】 基于mvc三层架构和ajax技术实现最简单的文件上传 事件管理
服务器文档下载zip格式 刚好这次项目中遇到了这个东西,就来弄一下,挺简单的,但是前台调用的时候弄错了,浪费了大半天的时间,本人也是菜鸟一枚.开始吧.(MVC的) @using Rattan.Co ...
- 基于Lucene查询原理分析Elasticsearch的性能
前言 Elasticsearch是一个很火的分布式搜索系统,提供了非常强大而且易用的查询和分析能力,包括全文索引.模糊查询.多条件组合查询.地理位置查询等等,而且具有一定的分析聚合能力.因为其查询场景 ...
- Yii的学习(3)--查询生成器 (Query Builder)
原文地址:http://www.yiiframework.com/doc/guide/1.1/en/database.query-builder 不过原文是英文的,Yii的官网没有翻译这一章,自己就尝 ...
- mysql分页查询详解
我们做的后端项目一般都会有admin管理端,当管理端将要展示数据的时候,就需要用到分页.所以分页的考查在面试中也相当多.在mysql中进行分页查询时,一般会使用limit查询,而且通常查询中都会使用o ...
随机推荐
- 时间序列知识图谱-《利用Python进行数据分析》
所有内容整理自<利用Python进行数据分析>,使用MindMaster Pro 7.3制作,emmx格式,源文件已经上传Github,需要的同学转左上角自行下载或者右击保存图片. 其他章 ...
- 《java常用设计模式之----单例模式》
一.简介 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创 ...
- HashMap源码实现分析
HashMap源码实现分析 一.前言 HashMap 顾名思义,就是用hash表的原理实现的Map接口容器对象,那什么又是hash表呢. 我们对数组都很熟悉,数组是一个占用连续内存的数据结构,学过C的 ...
- 题解 SP2713 【GSS4 - Can you answer these queries IV】
用计算器算一算,就可以发现\(10^{18}\)的数,被开方\(6\)次后就变为了\(1\). 所以我们可以直接暴力的进行区间修改,若这个数已经到达\(1\),则以后就不再修改(因为\(1\)开方后还 ...
- C#串模板
c# 6.0 的语言特性,功能类似string.formate,更方便的地方在于不要像format一样使用索引,可以直接使用变量. 使用方法如下: string name = "zhangs ...
- 2020数字中国创新大赛虎符网络安全赛道-pwn count
比赛结束前半个小时才看的题,等我做出来比赛已经结束了.难受Orz 本地文件无法执行,远程调试. 题目大概意思就是让你计算200道四则运算.(实际上格式是固定的.先乘一次然后再加两次).200道题都正确 ...
- 枚举-称硬币POJ1013
#include <iostream> #include<string.h> using namespace std; char Lleft[][]; char Lright[ ...
- Python for循环通过序列索引迭代
Python for 循环通过序列索引迭代: 注:集合 和 字典 不可以通过索引进行获取元素,因为集合和字典都是无序的. 使用 len (参数) 方法可以获取到遍历对象的长度. 程序: strs = ...
- 部分浏览器 set-cookie 不成功踩坑记录
事件起因: 公司正在做一个sso的单点登录的项目,做完之后,在测试阶段,不同的终端的兼容测试时候,好几个不同的浏览器出现了不同的问题,有登录之后自动退出,有登陆不成功等问题. 在 pc 端只有 uc ...
- 程序员面试:C/C++求职者必备 20 道面试题,一道试题一份信心!
面试真是痛并快乐的一件事,痛在被虐的体无完肤,快乐在可以短时间内积累很多问题,加速学习. 在我们准备面试的时候,遇到的面试题有难有易,不能因为容易,我们就轻视,更不能因为难,我们就放弃.我们面对高薪就 ...