在《Kafka日志文件目录布局》中提到Kafka中每个日志分段文件对应了两个索引文件——xxx.index(偏移量索引文件用来建立消息偏移量到物理地址之间的映射关系)和xxx.timeindex(用于根据指定的时间戳来查找对应的偏移量信息)。
Kafka中的索引文件以稀疏索引(sparse index)的方式构造消息的索引,每当写入一定量(由broker端参数log.index.interval.bytes指定,默认值为4096,即4KB)的消息时,偏移量索引文件和时间戳索引文件分别增加一个偏移量索引项和时间戳索引项。
稀疏索引通过MappedByteBuffer将索引文件映射到内存中,以加快索引的查询速度。偏移量索引文件的偏移量是单调递增的,查询指定偏移量时,使用二分查找法来快速定位偏移量的位置,如果指定的偏移量不在索引文件中,则会返回小于指定偏移量的最大偏移量。时间戳索引文件中的时间戳也保持严格的单调递增,查询指定时间戳时,也根据二分查找法来查找不大于该时间戳的最大偏移量,至于要找到对应的物理文件位置还需要根据偏移量索引文件来进行再次定位。稀疏索引的方式是在磁盘空间、内存空间、查找时间等多方面之间的一个折中。
日志分段文件达到一定的条件时需要进行切分,那么其对应的索引文件也需要进行切分。日志分段文件切分包含以下几个条件,满足其一即可:
- 当时日志分段文件的大小超过了broker端参数log.segment.bytes配置的值,默认为1GB
- 当前日志分段中消息的最大时间戳与当前系统的时间戳的差值大于log.roll.ms或log.roll.hours参数配置的值。默认情况下,只配置了log.roll.hours参数,默认7天
- 偏移量索引文件或时间戳索引文件的大小达到 broker端参数log.index.size.max.bytes配置的值,默认10MB
- 追加的消息偏移量与当前日志分段的偏移量之间的差值大于Integer.MAX_VALUE(offset - baseoffset > Integer.MAX_VALUE)
对非当前活跃的日志分段而言,其对应的索引文件内容已经固定而不需要再写入索引项,所以会被设定为只读。而对当前活跃的日志分段(activeSegment)而言,索引文件还会追加更多的索引项,所以被设定为可读写。在索引文件切分的时候,Kafka会关闭当前正在写入的索引文件并置为只读模式,同时以可读定的模式创建新的索引文件,索引文件的大小由broker端参数log.index.size.max.bytest配置。
注意:Kafka在创建索引文件的时候会为其预分配log.index.size.max.bytes大小的空间,注意这一点与日志分段文件不同,只有当索引文件进行切分的时候,kafka才会把该索引文件裁剪到实际的数据大小。也就是说,与当前活跃的日志分段对应的索引文件的大小固定为log.index.size.max.bytes,而其余日志分段对应的索引文件的大小为实际的占用空间。