Kafka索引机制

Kafka索引机制

数据文件的分段和索引

kafka解决查询效率的手段之一是将数据文件分段存储,可以配置每一个文件的大小。每一个端段单独放在一个.log的文件中,数据文件命名是20个字符的长度,以每一个分段文件开始的最下offset来命名,其他位置用0填充。最初始的文件是00000000000000000000.log命名的,比如下一个log中的第一条消息的offset是18987,则该log文件的命名是00000000000000018987.log

其中每一个log文件的大小默认是1GB,每生成一个log文件就会对应产生一个offsetIndex文件,是和log文件的命名相同的。这样在进行消息检索的时候可以快速利用二分的方法进行查找,定位到某一个分段文件中。

Partition在服务器上的表现形式就是一个一个的文件夹,每个partition的文件夹下面会有多组segment文件,每组segment文件又包含.index文件、.log文件、.timeindex文件(早期版本中没有)三个文件, log文件就实际是存储message的地方,而index和timeindex文件为索引文件,用于检索消息。

Message结构
上面说到log文件就实际是存储message的地方,我们在producer往kafka写入的也是一条一条的message,那存储在log中的message是什么样子的呢?消息主要包含消息体、消息大小、offset、压缩类型……等等!我们重点需要知道的是下面三个:
  1、 offset:offset是一个占8byte的有序id号,它可以唯一确定每条消息在parition内的位置!
  2、 消息大小:消息大小占用4byte,用于描述消息的大小。
  3、 消息体:消息体存放的是实际的消息数据(被压缩过),占用的空间根据具体的消息而不一样。

存储策略
  无论消息是否被消费,kafka都会保存所有的消息。那对于旧数据有什么删除策略呢?
  1、 基于时间,默认配置是168小时(7天)。
  2、 基于大小,默认配置是1073741824。
  需要注意的是,kafka读取特定消息的时间复杂度是O(1),所以这里删除过期的文件并不会提高kafka的性能!

数据文件的分段使得可以在一个较小的数据文件中找到对应的offset的message了。在index文件中的索引实际也是稀疏性的,并不是全部都建立索引的。(这也是考虑到index文件在加载到内存的时候,能不占用大量的内存和CPU资源)索引文件中包含的若干条目,每个条目表示的数据文件中的一条message的索引——是当前的message在数据文件的offset和在文件的position(message在文件中的绝对位置信息)的对应关系。如下图所示:

其中00000000000000000000.index文件中的3,4597对应到00000000000000000000.log文件中的第三条消息,并且该消息的绝对位置是4597。但是如果消费者想要 获取5,7912的话,此时index文件中并没有5,所以根据二分查找,先找到3的位置,在进行顺序扫描从而找到5,7912的message。

index文件中并没有为每一条message建立索引。而是采用了稀疏存储的方式,每隔一定字节的数据建立一条索引,这样的话就是避免了索引文件占用过多的空间和资源,从而可以将索引文件保留到内存中。缺点是没有建立索引的数据在查询的过程中需要小范围内的顺序扫描操作。

索引文件映射到内存的话,从而提高了查找的速度信息。

offsetIndex:

OffsetIndex索引文件的格式: 每一个索引项为8字节,其中相对offset占用4字节,消息的物理地址(position)占用4个字节

timeIndex:

TimeIndex索引文件格式:它是映射时间戳和相对offset, 时间戳和相对offset作为entry,供占用12字节,时间戳占用8字节,相对offset占用4字节,这个索引也是稀疏索引,没有保存全部的消息的entry

  • Kafka从0.10.0.0版本起,在消息内新增加了个timestamp字段,
  • 在Kafka 0.10.1.0以前(不包含0.10.1.0),对于一个Topic而言,其Log Segment是由一个.log文档和一个.index文档组合而成,分别用来存储具体的消息数据和对应的偏移量
  • 从Kafka 0.10.1.0开始,对于日志文档,新增一个.timeindex文档,即每个Segment分别由.log、.index和.timeindex这三个文档组成。

kafka时间戳的作用

  • 基于时间戳的日志切分策略
  • 基于时间戳的日志清除策略
  • 根据时间戳来定位消息:之前的索引文件是根据offset信息的,从逻辑语义上并不方便使用,引入了时间戳之后,Kafka支持根据时间戳来查找定位消息

kafkamysql索引机制的不同:

既然InnoDB的索引这么厉害,那么作为后起之秀的Kafka不采用呢?

我们还要考虑一个问题:InnoDB中维护索引的代价比Kafka中的要高。

Kafka中当有新的索引文件建立的时候ConcurrentSkipListMap才会更新,而不是每次有数据写入时就会更新,这块的维护量基本可以忽略

B+树中数据有插入、更新、删除的时候都需要更新索引,还会引来“页分裂”等相对耗时的操作。Kafka中的索引文件也是顺序追加文件的操作,和B+树比起来工作量要小很多。

说到底还是应用场景不同所决定的。MySQL中需要频繁地执行CRUD的操作,CRUD是MySQL的主要工作内容,而为了支撑这个操作需要使用维护量大很多的B+树去支撑。

Kafka中的消息一般都是顺序写入磁盘,再到从磁盘顺序读出(不深入探讨page cache等),他的主要工作内容就是:写入+读取,很少有检索查询的操作

换句话说,检索查询只是Kafka的一个辅助功能,不需要为了这个功能而去花费特别太的代价去维护一个高level的索引。

前面也说过,Kafka中的这种方式是在磁盘空间、内存空间、查找时间等多方面之间的一个折中。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值