本文主要有两大块内容:
- patition里的segment file
- 如何查找一条消息
- partition:topic物理上的分组,一个topic下可以有多个partition,每个partion是有序的
- segment:每个patition由多个segment file组成
- offset:partition中的每个消息都有一个连续的序列号叫做offset,用于标识唯一一条partition里的消息
- message:kafka中最小的存储单位,a commit log.
patition里的segment file partition里的segment file是以文件夹的形式存储在Broker上的,它们大小相等(具体大小可以通过config/server.properties中进行设置)。
segment file的特点
- 组成。由两部分组成,分别是index file与data file,这两个文件一一对应,后缀分别为.index与.log
- 命名。partition的第一个segment从0开始,后续每个segment文件名为上一个segment文件最后一条消息的offset,20位数字字符长度,不足用0填充。
文章图片
index file与data file的关系
先看一张图
文章图片
索引文件中存储着元数据,数据文件存储着消息,根据索引文件中的元数据我们可以快速定位到数据文件里相应的消息。以索引文件中的3,497为例,3指的是在数据文件中的第3个segment,它是一个逻辑地址;而497指的是该消息在segment里的物理偏移地址为497。
从上图我们还可以知道在00000000000000368769.log文件里的Message368772这个segment在全局partition表示第368772个message,也就是通过文件名我们就可以知道它所在的全局offset。
data file物理结构
文章图片
在图里我们可以清楚地知道data file里记录着消息的大小(size)与具体内容(payload)等信息
如何查找一条消息 partition的消息文件为什么要分别生成index file与data file这两个文件呢?很大一部分原因就是为了方便消息的查找。这里也能看出kafka可以高效查找消息的两个手段:分段与索引。
数据文件的分段
【kafka-partition中的数据文件】这个是比较好理解的,加入有100条message,它们的offset是从0到99,假设将数据文件分为5段,第一段为0-19,第二段为20-39,依次类推,每段放在一个单独的数据文件里面,数据文件以该段中最小的offset命名。这样在查找指定offset的Message的时候,用二分查找就可以定位到该Message在哪个段中。
为数据文件建索引
数据文件分段使得可以在一个较小的数据文件中查找对应offset的message了,但是这依然需要顺序扫描才能找到对应offset的message。为了进一步提高查找的效率,Kafka为每个分段后的数据文件建立了索引文件,文件名与数据文件的名字是一样的,只是文件扩展名为.index。
索引文件中包含若干个索引条目,每个条目表示数据文件中一条message的索引。索引包含两个部分(均为4个字节的数字),分别为相对offset和position。
- 相对offset:因为数据文件分段以后,每个数据文件的起始offset不为0,相对offset表示这条message相对于其所属数据文件中最小的offset的大小。举例,分段后的一个数据文件的offset是从20开始,那么offset为25的message在index文件中的相对offset就是25-20 = 5。存储相对offset可以减小索引文件占用的空间。
- position:表示该条message在数据文件中的绝对位置。只要打开文件并移动文件指针到这个position就可以读取对应的message了。
假设我们想读取offset=368776的message(参考第图二)
- 查找segment file
当offset=368776时定位到00000000000000368769.index|log
- 通过segment file查找message
segment index file并没有为数据文件中的每条message建立索引,而是采取稀疏索引存储方式,每隔一定字节的数据建立一条索引,它减少了索引文件大小,通过map可以直接内存操作,稀疏索引为数据文件的每个对应message设置一个元数据指针,它比稠密索引节省了更多的存储空间