offset range 查询

我们在实际使用过程中经常需要查询某个topic的某分区的offset的range

命令行:

  1. kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list xxxx:9092 -topic xxxtopic --time -2
  2. kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list xxxx:9092 -topic xxxtopic --time -1

-1 -2 的特殊含义:

  1. public class ListOffsetRequest extends AbstractRequest {
  2. public static final long EARLIEST_TIMESTAMP = -2L;
  3. public static final long LATEST_TIMESTAMP = -1L;
  4. }

客户端

KafkaConsumer.endOffsets(Collection)

KafkaConsumer.beginningOffsets(Collection)

Fetcher.beginningOrEndOffset(Collection, long, long)

Fetcher.retrieveOffsetsByTimes(Map<TopicPartition, Long>, long, boolean)

Fetcher.sendListOffsetRequests(boolean, Map<TopicPartition, Long>)

  1. // Group the partitions by node.
  2. final Map<Node, Map<TopicPartition, Long>> timestampsToSearchByNode = new HashMap<>();
  3. for (Map.Entry<TopicPartition, Long> entry: timestampsToSearch.entrySet()) {
  4. TopicPartition tp = entry.getKey();
  5. PartitionInfo info = metadata.fetch().partition(tp);
  6. if (info == null) {
  7. metadata.add(tp.topic());
  8. log.debug("Partition {} is unknown for fetching offset, wait for metadata refresh", tp);
  9. return RequestFuture.staleMetadata();
  10. } else if (info.leader() == null) {
  11. log.debug("Leader for partition {} unavailable for fetching offset, wait for metadata refresh", tp);
  12. return RequestFuture.leaderNotAvailable();
  13. } else {
  14. Node node = info.leader();
  15. Map<TopicPartition, Long> topicData = timestampsToSearchByNode.get(node);
  16. if (topicData == null) {
  17. topicData = new HashMap<>();
  18. timestampsToSearchByNode.put(node, topicData);
  19. }
  20. topicData.put(entry.getKey(), entry.getValue());
  21. }
  22. }
  23. final RequestFuture<Map<TopicPartition, OffsetData>> listOffsetRequestsFuture = new RequestFuture<>();
  24. final Map<TopicPartition, OffsetData> fetchedTimestampOffsets = new HashMap<>();
  25. final AtomicInteger remainingResponses = new AtomicInteger(timestampsToSearchByNode.size());
  26. for (Map.Entry<Node, Map<TopicPartition, Long>> entry : timestampsToSearchByNode.entrySet()) {
  27. sendListOffsetRequest(entry.getKey(), entry.getValue(), requireTimestamps)
  28. .addListener(new RequestFutureListener<Map<TopicPartition, OffsetData>>() {
  29. @Override
  30. public void onSuccess(Map<TopicPartition, OffsetData> value) {
  31. synchronized (listOffsetRequestsFuture) {
  32. fetchedTimestampOffsets.putAll(value);
  33. if (remainingResponses.decrementAndGet() == 0 && !listOffsetRequestsFuture.isDone())
  34. listOffsetRequestsFuture.complete(fetchedTimestampOffsets);
  35. }
  36. }
  37. @Override
  38. public void onFailure(RuntimeException e) {
  39. synchronized (listOffsetRequestsFuture) {
  40. // This may cause all the requests to be retried, but should be rare.
  41. if (!listOffsetRequestsFuture.isDone())
  42. listOffsetRequestsFuture.raise(e);
  43. }
  44. }
  45. });
  46. }
  47. return listOffsetRequestsFuture;

简单点说:就是找到leader节点然后给其发送ListOffsetRequest请求。这个请求是按时间进行offset定位。

broker端

KafkaApis.handleListOffsetRequestV1AndAbove(request: RequestChannel.Request)

查询最新offset

这个值应该是在生产的时候维护好的

  1. val lastFetchableOffset = offsetRequest.isolationLevel match {
  2. case IsolationLevel.READ_COMMITTED => localReplica.lastStableOffset.messageOffset
  3. case IsolationLevel.READ_UNCOMMITTED => localReplica.highWatermark.messageOffset
  4. }

这个地方也能反映出 LEO,LSO,highwater的区别!!

查询最早offset

kafka.log.Log.fetchOffsetsByTimestamp(targetTimestamp: Long)

这个值应该是在生产的时候维护好的

  1. @threadsafe
  2. class Log(@volatile var dir: File,
  3. @volatile var config: LogConfig,
  4. @volatile var logStartOffset: Long,
  5. @volatile var recoveryPoint: Long,
  6. scheduler: Scheduler,
  7. brokerTopicStats: BrokerTopicStats,
  8. time: Time,
  9. val maxProducerIdExpirationMs: Int,
  10. val producerIdExpirationCheckIntervalMs: Int,
  11. val topicPartition: TopicPartition,
  12. val producerStateManager: ProducerStateManager,
  13. logDirFailureChannel: LogDirFailureChannel) extends Logging with KafkaMetricsGroup {
  14. // ......
  15. if (targetTimestamp == ListOffsetRequest.EARLIEST_TIMESTAMP)
  16. return Some(TimestampOffset(RecordBatch.NO_TIMESTAMP, logStartOffset))

按时间戳查询offset

先确定target segment

  1. val targetSeg = {
  2. // Get all the segments whose largest timestamp is smaller than target timestamp
  3. val earlierSegs = segmentsCopy.takeWhile(_.largestTimestamp < targetTimestamp)
  4. // We need to search the first segment whose largest timestamp is greater than the target timestamp if there is one.
  5. if (earlierSegs.length < segmentsCopy.length)
  6. Some(segmentsCopy(earlierSegs.length))
  7. else
  8. None
  9. }

再到seg的index根据时间查找

LogSegment.findOffsetByTimestamp(timestamp: Long, startingOffset: Long)

先定位到index然后再二分查找


  1. // LogSegment.scala
  2. val timestampOffset = timeIndex.lookup(timestamp)
  3. val position = index.lookup(math.max(timestampOffset.offset, startingOffset)).position
  4. // AbstractIndex.scala
  5. /**
  6. * Lookup lower and upper bounds for the given target.
  7. */
  8. private def indexSlotRangeFor(idx: ByteBuffer, target: Long, searchEntity: IndexSearchEntity): (Int, Int) = {
  9. // check if the index is empty
  10. if(_entries == 0)
  11. return (-1, -1)
  12. // check if the target offset is smaller than the least offset
  13. if(compareIndexEntry(parseEntry(idx, 0), target, searchEntity) > 0)
  14. return (-1, 0)
  15. // binary search for the entry
  16. var lo = 0
  17. var hi = _entries - 1
  18. while(lo < hi) {
  19. val mid = ceil(hi/2.0 + lo/2.0).toInt
  20. val found = parseEntry(idx, mid)
  21. val compareResult = compareIndexEntry(found, target, searchEntity)
  22. if(compareResult > 0)
  23. hi = mid - 1
  24. else if(compareResult < 0)
  25. lo = mid
  26. else
  27. return (mid, mid)
  28. }
  29. (lo, if (lo == _entries - 1) -1 else lo + 1)
  30. }

offset range 查询的更多相关文章

  1. 【MySQL】SQL优化系列之 in与range 查询

    首先我们来说下in()这种方式的查询 在<高性能MySQL>里面提及用in这种方式可以有效的替代一定的range查询,提升查询效率,因为在一条索引里面,range字段后面的部分是不生效的. ...

  2. MySQL SQL优化之in与range查询【转】

    本文来自:http://myrock.github.io/ 首先我们来说下in()这种方式的查询.在<高性能MySQL>里面提及用in这种方式可以有效的替代一定的range查询,提升查询效 ...

  3. Elasticsearch使用filter进行匹配关系and,or,not,range查询

    RESTful接口URL的格式: http://localhost:9200/<index>/<type>/[<id>] 其中index.type是必须提供的. i ...

  4. golang LMDB入门例子——key range查询

    如下,使用gomb库 package main import ( "bytes" "fmt" "io/ioutil" "os&qu ...

  5. 67.ORM查询条件:range的使用,使用make_aware将navie time 转换为aware time

    模型的定义,models.py文件中示例代码如下: from django.db import models # 在定义模型的类时,一定要继承models.Model class Category(m ...

  6. 服务器文档下载zip格式 SQL Server SQL分页查询 C#过滤html标签 EF 延时加载与死锁 在JS方法中返回多个值的三种方法(转载) IEnumerable,ICollection,IList接口问题 不吹不擂,你想要的Python面试都在这里了【315+道题】 基于mvc三层架构和ajax技术实现最简单的文件上传 事件管理

    服务器文档下载zip格式   刚好这次项目中遇到了这个东西,就来弄一下,挺简单的,但是前台调用的时候弄错了,浪费了大半天的时间,本人也是菜鸟一枚.开始吧.(MVC的) @using Rattan.Co ...

  7. 基于Lucene查询原理分析Elasticsearch的性能

    前言 Elasticsearch是一个很火的分布式搜索系统,提供了非常强大而且易用的查询和分析能力,包括全文索引.模糊查询.多条件组合查询.地理位置查询等等,而且具有一定的分析聚合能力.因为其查询场景 ...

  8. Yii的学习(3)--查询生成器 (Query Builder)

    原文地址:http://www.yiiframework.com/doc/guide/1.1/en/database.query-builder 不过原文是英文的,Yii的官网没有翻译这一章,自己就尝 ...

  9. mysql分页查询详解

    我们做的后端项目一般都会有admin管理端,当管理端将要展示数据的时候,就需要用到分页.所以分页的考查在面试中也相当多.在mysql中进行分页查询时,一般会使用limit查询,而且通常查询中都会使用o ...

随机推荐

  1. docker环境部署mysql

    参考文档 docker官方:https://hub.docker.com/_/mysql/?tab=description 部署步骤 1. 拉取镜像 这里我拉取了tag为5.7的镜像 docker p ...

  2. C++语法小记---重载逻辑操作符

    重载逻辑操作符 不建议重载逻辑操作符 原因:无法实现逻辑操作符的短路功能(即:不需要计算完全部表达式就可以得出结果) 逻辑操作符:|| && 操作符重载本质上是函数调用,而进行函数调用 ...

  3. 放弃dagger?Anrdoi依赖注入框架koin

    Koin 是什么 Koin 是为 Kotlin 开发者提供的一个实用型轻量级依赖注入框架,采用纯 Kotlin 语言编写而成,仅使用功能解析,无代理.无代码生成.无反射. 官网地址 优势 依赖注入好处 ...

  4. justoj connect(边的处理)

    CONNECT https://oj.ismdeep.com/contest/problem?id=1702&pid=2 Problem Description 有nn个顶点,每个顶点有自己的 ...

  5. 如何从Python负零基础到精通数据分析

    一.为什么学习数据分析 1.运营的尴尬:运营人需要一个硬技能每个初入行的新人都会察觉到,运营是一个似乎并没有自己的核心竞争力和安全感的工作.因为每天的工作好像都被各种琐事所围绕,而只有一个主题是永恒不 ...

  6. javascrip jason

    JavaScript JSONJSON 是用于存储和传输数据的格式. JSON 通常用于服务端向网页传递数据 . <html><head><meta http-equiv ...

  7. IDEA中配置Project Structure

    本文主要介绍在IDEA中怎么配置项目Project Structure. 若文中有所偏错,望能够留言指正,不胜感激. 不再赘述,直接进入正题: 1. 打开IDEA的Project Structure( ...

  8. 性能分析(1)- Java 进程导致 CPU 使用率升高,问题怎么定位?

    性能分析小案例系列,可以通过下面链接查看哦 ps:这些分析小案例不能保证百分比正确,是博主学习过程中的总结,仅做参考 前提 本机有一个很占用 CPU 的项目,放在了 Tomcat 下启动着 如何定位 ...

  9. Python 字典(Dictionary) cmp()方法

    Python 字典(Dictionary) cmp()方法 描述 Python 字典的 cmp() 函数用于比较两个字典元素.高佣联盟 www.cgewang.com 语法 cmp()方法语法: cm ...

  10. PHP is_writable() 函数

    定义和用法 is_writable() 函数检查指定的文件是否可写. 如果文件可写,该函数返回 TRUE. 语法 is_writable(file) 参数 描述 file 必需.规定要检查的文件. 提 ...