本文主要有两大块内容:
- patition里的segment file
- 如何查找一条消息
先看下几个基本的概念:
- partition:topic物理上的分组,一个topic下可以有多个partition,每个partition是有序的
- segment:每个patition由多个segment file组成
- offset:partition中的每个消息都有一个连续的序列号叫做offset,用于标识唯一一条partition里的消息
- message:kafka中最小的存储单位,a commit log.
kafka的message是以topic为基本单位,不同的topic之间的相互独立的,每个topic又可以分为几个不同的partition,每个partition存储一部分message。
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也就是368769+3=368772,它是一个逻辑地址;而497指的是该消息在segment里的物理偏移地址为497。
三,data file物理结构
在图里我们可以清楚地知道data file里记录着消息的大小(size)与具体内容(payload)等信息
如何查找一条消息
partition的消息文件为什么要分别生成index file与data file这两个文件呢?很大一部分原因就是为了方便消息的查找。这里也能看出kafka可以高效查找消息的两个手段:分段与索引。
一,数据文件的分段
这个是比较好理解的,加入有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查找message
假设我们想读取offset为7的消息
- 首先使用二分查找确定它在哪个LogSegment中,这里是第一个segment中(00000000000000000000.log|index)
- 打开这个segment的index文件,也就是用二分查找找到offset小于或等于指定offset的索引条目中最大的那个offset,这里offset为6的那个索引是我们要找的,通过索引文件我们知道offset为6的message在数据文件中的位置是9807.
- 打开数据文件,从位置9807的那个地方开始顺序扫描直到找到offset为7的那条message。
这套机制是建立在offset是有序的。索引文件被映射到内存中,所以查找速度还是很快的。
segment index file并没有为数据文件中的每条message建立索引,而是采取稀疏索引存储方式,每隔一定字节的数据建立一条索引,它减少了索引文件大小,通过map可以直接内存操作,稀疏索引为数据文件的每个对应message设置一个元数据指针,它比稠密索引节省了更多的存储空间。一句话,Kafka的Message存储采用了分区(partition),分段(LogSegment)和稀疏索引这几个手段来达到了高效性。
参考文章:Kafka的Log存储解析
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。