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. [jvm] -- 垃圾收集器篇

    垃圾收集器 Serial 收集器 单线程收集器,不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( "Stop The ...

  2. 题解 洛谷 P3521 【[POI2011]ROT-Tree Rotations】

    给定一棵二叉树,叶子节点有权值,可以进行若干次交换一个节点的左右儿子的操作,使前序遍历叶子的逆序对最少. 考虑一个节点下子树逆序对的产生: ① 只在左子树中产生. ② 只在右子树中产生. ③ 在左子树 ...

  3. Sts 授权直传阿里云 OSS-.net core实现

    前言 磁盘怎么又满了?赶紧 快 打电话给运维扩容扩容扩容!这个问题已经是我入职新公司两个月来,第 3 次听到了.经过一通了解,事情原来是这样的.虽然我们使用了阿里云的 OSS 对象存储服务,但是为了不 ...

  4. .Net Core in Docker极简入门(下篇)

    Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 Docker-Compose 代码修改 yml file up & down 镜像仓库 最后 前言 上一篇[. ...

  5. python map函数、filter函数、reduce函数

    1.map函数:map(func,可迭代对象): ①func可以是自定义的函数,也可以是功能简单的匿名函数(通过lambda定义) ②处理逻辑:表示将传入的可迭代对象依次循环,将每个元素按照传入的fu ...

  6. Docker引言,由来,思想

    引言 我本地运行没问题啊? 环境不一致? 哪个哥们又写死循环了?,怎么这么卡? 在多用户操作系统下,会相互影响 淘宝在双11的时候,用户量暴增 运维成果过高的问题 学习一门技术,学习安装成本高 关于安 ...

  7. 详解 MySQL 面试核心知识点

    一.常见存储引擎 1.1 InnoDB InnoDB 是 MySQL 5.5 之后默认的存储引擎,它具有高可靠.高性能的特点,主要具备以下优势: DML 操作完全遵循 ACID 模型,支持事务,支持崩 ...

  8. PHP系列之钩子

    PHP 提供的钩子 PHP 和 Zend Engine 为扩展提供了许多不同的钩子,这些扩展允许扩展开发人员以 PHP userland 无法提供的方式控制 PHP 运行时. 本章将展示各种钩子和从扩 ...

  9. 女生学Java编程是什么感受?

    那我就代表女生来说说感受 在编程的世界很难遇到好看的帅哥 记得当年15年7月4号是我实习生入职的日子,因为是校企合作,所以没有面试.老师推荐.直接入职.刚来北京第一个感觉就是人多,还有就是热.刚到公司 ...

  10. Python os.pathconf() 方法

    概述 os.pathconf() 方法用于返回一个打开的文件的系统配置信息.高佣联盟 www.cgewang.com Unix 平台下可用. 语法 fpathconf()方法语法格式如下: os.fp ...