Kafka原理浅析-根据时间戳查询消息

一、前言

近日被问到Kafka根据时间戳是如何进行消息查询的,整理一圈下来后,发现涉及一些知识点,因此总结此文

二、消息落盘

要想了解kafka是如何根据时间戳查询消息的,那就需先了解消息是如何落盘的。把场景聚焦在这个点上的话,涉及的文件有3个:

  • xxxxxxxx.log
  • xxxxxxxx.index
  • xxxxxxxx.timeindex

可以拿我本机中topic2第0号partition举例:

xxxxxxxx.log文件不用多说,这个属于Kafka的SOT(Source Of True),消息的header、body均存储在这个文件

xxxxxxxx.index 文件,就是大名鼎鼎的稀疏索引了,它的entry是由<offset, physicalPosition>组成的,也就是位点+其对应的文件物理位置;所谓稀疏,是指并不是每条消息都会生成一条这样的索引记录,而是xxxxxxxx.log文件每写入4K(磁盘都是4K对齐的)的数据,便会生成一条稀疏索引

xxxxxxxx.timeindex 文件,就是时间索引了,它的entry是由<timestamp, offset>组成的,也就是时间戳+位点。值得一提的是,时间索引的生成频率与稀疏索引是完全对齐的

简单贴一段索引的生成代码,可以看到这两个索引要么不写入,要么就一起写入

复制代码
// 类路径: kafka/log/LogSegment.scala

// append an entry to the index (if needed)
if (bytesSinceLastIndexEntry > indexIntervalBytes) {
  offsetIndex.append(largestOffset, physicalPosition)
  timeIndex.maybeAppend(maxTimestampSoFar, offsetOfMaxTimestampSoFar)
  bytesSinceLastIndexEntry = 0
}

三、根据时间查询

查询的时候,就要用到这两个索引文件,当然这两个文件肯定不能精确定位目标消息,但是其可以帮助粗略定位

  1. 查询.timeindex文件,根据目标时间戳,查询第一个比目标时间戳小的索引(因为时间戳是升序的,因此此处使用二分查找高效定位),从而可获取到这个索引的位点信息 offsetMin
  2. 使用这个 offsetMin 位点查询.index文件,因为index索引文件也是根据offset升序的,同样使用二分查找获取对应的文件物理 position
  3. 通过 position 信息查询 .log 文件,逐步向后读取,直到找到第一个与目标时间戳相等或大于目标时间差的消息,而后返回其位点

总结:本文粗枝大叶地将按照时间戳查询消息的流程过了一遍,很多细节没有展开(尤其是涉及文件操作的),希望可以帮助大家对其有个整体概念及认识