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 ...
随机推荐
- docker环境部署mysql
参考文档 docker官方:https://hub.docker.com/_/mysql/?tab=description 部署步骤 1. 拉取镜像 这里我拉取了tag为5.7的镜像 docker p ...
- C++语法小记---重载逻辑操作符
重载逻辑操作符 不建议重载逻辑操作符 原因:无法实现逻辑操作符的短路功能(即:不需要计算完全部表达式就可以得出结果) 逻辑操作符:|| && 操作符重载本质上是函数调用,而进行函数调用 ...
- 放弃dagger?Anrdoi依赖注入框架koin
Koin 是什么 Koin 是为 Kotlin 开发者提供的一个实用型轻量级依赖注入框架,采用纯 Kotlin 语言编写而成,仅使用功能解析,无代理.无代码生成.无反射. 官网地址 优势 依赖注入好处 ...
- justoj connect(边的处理)
CONNECT https://oj.ismdeep.com/contest/problem?id=1702&pid=2 Problem Description 有nn个顶点,每个顶点有自己的 ...
- 如何从Python负零基础到精通数据分析
一.为什么学习数据分析 1.运营的尴尬:运营人需要一个硬技能每个初入行的新人都会察觉到,运营是一个似乎并没有自己的核心竞争力和安全感的工作.因为每天的工作好像都被各种琐事所围绕,而只有一个主题是永恒不 ...
- javascrip jason
JavaScript JSONJSON 是用于存储和传输数据的格式. JSON 通常用于服务端向网页传递数据 . <html><head><meta http-equiv ...
- IDEA中配置Project Structure
本文主要介绍在IDEA中怎么配置项目Project Structure. 若文中有所偏错,望能够留言指正,不胜感激. 不再赘述,直接进入正题: 1. 打开IDEA的Project Structure( ...
- 性能分析(1)- Java 进程导致 CPU 使用率升高,问题怎么定位?
性能分析小案例系列,可以通过下面链接查看哦 ps:这些分析小案例不能保证百分比正确,是博主学习过程中的总结,仅做参考 前提 本机有一个很占用 CPU 的项目,放在了 Tomcat 下启动着 如何定位 ...
- Python 字典(Dictionary) cmp()方法
Python 字典(Dictionary) cmp()方法 描述 Python 字典的 cmp() 函数用于比较两个字典元素.高佣联盟 www.cgewang.com 语法 cmp()方法语法: cm ...
- PHP is_writable() 函数
定义和用法 is_writable() 函数检查指定的文件是否可写. 如果文件可写,该函数返回 TRUE. 语法 is_writable(file) 参数 描述 file 必需.规定要检查的文件. 提 ...