一、日志的存储
Kafka的消息以日志文件的形式进行存储。不同主题下不同分区的消息是分开存储的。同一个分区的不同副本也是以日志的形式,分布在不同的broker上存储。
日志的存储是以副本为单位的,每个副本对应一个log对象,一个log又划分为多个logSegment进行存储。
kafka会在指定的目录下创建对应的文件夹,命名规则为“topic名称-分区编号”。
logSegment代表逻辑上的一组文件,这组文件就是.log、.index、.timeindex这三个不同文件扩展名,但是同文件名的文件。
- .log存储消息
- .index存储消息的索引
- .timeIndex,时间索引文件,通过时间戳做索引。
这三个文件配合使用,用来保存和消费时快速查找消息。
命名规则为.log文件中第一条消息的前一条消息偏移量,也称为基础偏移量,左边补0,补齐20位。
比如说第一个LogSegement的日志文件名为00000000000000000000.log,假如存储了200条消息后,达到了log.segment.bytes配置的阈值(默认1个G),那么将会创建新的logSegment,文件名为00000000000000000200.log。以此类推。另外即使没有达到log.segment.bytes的阈值,而是达到了log.roll.ms或者log.roll.hours设置的时间触发阈值,同样会触发产生新的logSegment。
二、日志定位
日志定位的过程如下:
1、根据offset定位logSegment。(kafka将基础偏移量也就是logsegment的名称作为key存在concurrentSkipListMap中)
2、根据logSegment的index文件查找到距离目标offset最近的被索引的offset的position x。
3、找到logSegment的.log文件中的x位置,向下逐条查找,找到目标offset的消息。
结合下图中例子,我再做详细的讲解:
(1)通过concurrentSkipListMap定位日志文件
(2)在对应索引文件里查到最接近的索引点
(3)在log文件中从索引点开始向下查找,知道找到指定的offset的数据
例子中consumer要消费offset=15的消息。我们假设目前可供消费的消息已经存储了三个logsegment,分别是00000000000000000,0000000000000000010,0000000000000000020。为了讲解方便,下面提到名称时,会把前面零去掉。
下面我们详细讲一下查找过程。
(1)kafka收到查询offset=15的消息请求后,通过二分查找,从concurrentSkipListMap中找到对应的logsegment名称,也就是10。
(2)从10.index中找到offset小于等于15的最大值,offset=14,它对应的position=340
(3)从10.log文件中物理位置340,顺序往下扫描文件,找到offset=15的消息内容。
可以看到通过稀疏索引,kafka既加快了消息查找的速度,也顾及了存储的开销。
更多内容: