本文次要讲述以下两局部内容:
kafka数据的存储形式;
kafka如何通过offset查找message。
1.前言
写介绍kafka的几个重要概念(能够参考之前的博文Kafka的简略介绍):
Broker:消息中间件解决结点,一个Kafka节点就是一个broker,多个broker能够组成一个Kafka集群;
Topic:一类音讯,例如page view日志、click日志等都能够以topic的模式存在,Kafka集群可能同时负责多个topic的散发;
Partition:topic物理上的分组,一个topic能够分为多个partition,每个partition是一个有序的队;
Segment:每个partition又由多个segment file组成;
offset:每个partition都由一系列有序的、不可变的音讯组成,这些音讯被间断的追加到partition中。partition中的每个音讯都有一个间断的序列号叫做offset,用于partition惟一标识一条音讯;
message:这个算是kafka文件中最小的存储单位,即是 a commit log。
kafka的message是以topic为根本单位,不同topic之间是互相独立的。每个topic又可分为几个不同的partition,每个partition存储一部的分message。topic与partition的关系如下:
topic
其中,partition是以文件夹的模式存储在具体Broker本机上。
2.partition中的数据文件
有了下面的介绍,上面咱们开始介绍Topic中partition的数据文件类型。
2.1.segment中的文件
对于一个partition(在Broker中以文件夹的模式存在),外面又有很多大小相等的segment数据文件(这个文件的具体大小能够在config/server.properties中进行设置),这种个性能够不便old segment file的疾速删除。
上面先介绍一下partition中的segment file的组成:
segment file 组成:由2局部组成,别离为index file和data file,这两个文件是一一对应的,后缀”.index”和”.log”别离示意索引文件和数据文件;
segment file 命名规定:partition的第一个segment从0开始,后续每个segment文件名为上一个segment文件最初一条音讯的offset,ofsset的数值最大为64位(long类型),20位数字字符长度,没有数字用0填充。如下图所示:
segment
对于segment file中index与data file对应关系图,这里咱们选用网上的一个图片,如下所示:
index
segment的索引文件中存储着大量的元数据,数据文件中存储着大量音讯,索引文件中的元数据指向对应数据文件中的message的物理偏移地址。以索引文件中的3,497为例,在数据文件中示意第3个message(在全局partition示意第368772个message),以及该音讯的物理偏移地址为497。
注:Partition中的每条message由offset来示意它在这个partition中的偏移量,这个offset并不是该Message在partition中理论存储地位,而是逻辑上的一个值(如下面的3),但它却惟一确定了partition中的一条Message(能够认为offset是partition中Message的id)。
2.2.message文件
message中的物理构造为:
message
2.3.数据文件的外部实现办法
Partition数据文件蕴含了若干上述格局的message,依照offset由小到大排列在一起,它实现的类是FileMessageSet,类图如下:
filemessageset
它的次要办法如下:
append: 把给定的ByteBufferMessageSet中的Message写入到这个数据文件中。
searchFor: 从指定的startingPosition开始搜寻,找到第一个Message判断其offset是大于或者等于指定的offset,并返回其在文件中的地位Position。它的实现形式是从startingPosition开始读取12个字节,别离是以后MessageSet的offset和size。如果以后offset小于指定的offset,那么将position向后挪动LogOverHead+MessageSize(其中LogOverHead为offset+messagesize,为12个字节)。
read:精确名字应该是slice,它截取其中一部分返回一个新的FileMessageSet。它不保障截取的地位数据的完整性。
sizeInBytes: 示意这个FileMessageSet占有了多少字节的空间。
truncateTo: 把这个文件截断,这个办法不保障截断地位的Message的完整性。
readInto: 从指定的绝对地位开始把文件的内容读取到对应的ByteBuffer中。
3.查找
3.1.遇到的问题
咱们首先试想一下,如果对于Kafka的一个topic而言,如果topic的partition中只有一个数据文件的话会怎么样?
新数据是增加在文件开端(调用FileMessageSet的append办法),不管文件数据文件有多大,这个操作永远都是O(1)的。
查找某个offset的Message(调用FileMessageSet的searchFor办法)是程序查找的。因而,如果数据文件很大的话,查找的效率就低。
3.2.如何去解决这个问题
由上述咱们晓得大数据培训,如果在topic的partition中只有一个数据文件的话,Kafka插入的效率尽管很高,然而查找的效率非常低,那么Kafka在外部是如何解决查找效率的的问题呢?对于这个问题,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了。
在kafka中,索引文件的实现类为OffsetIndex,它的类图如下:
offsetindex
次要的办法有:
append办法:增加一对offset和position到index文件中,这里的offset将会被转成绝对的offset。
lookup:用二分查找的形式去查找小于或等于给定offset的最大的那个offset
3.3.通过offset查找message
如果咱们想要读取offset=368776的message(见后面的第三个图),须要通过上面2个步骤查找。
查找segment file
00000000000000000000.index示意最开始的文件,起始偏移量(offset)为0.第二个文件00000000000000368769.index的音讯量起始偏移量为368770 = 368769 + 1.同样,第三个文件00000000000000737337.index的起始偏移量为737338=737337 + 1,其余后续文件顺次类推,以起始偏移量命名并排序这些文件,只有依据offset 二分查找文件列表,就能够疾速定位到具体文件。
当offset=368776时定位到00000000000000368769.index|log
通过segment file查找message
通过第一步定位到segment file,当offset=368776时,顺次定位到00000000000000368769.index的元数据物理地位和00000000000000368769.log的物理偏移地址,而后再通过00000000000000368769.log程序查找直到offset=368776为止。
segment index file并没有为数据文件中的每条message建设索引,而是采取稠密索引存储形式,每隔肯定字节的数据建设一条索引,它缩小了索引文件大小,通过map能够间接内存操作,稠密索引为数据文件的每个对应message设置一个元数据指针,它比浓密索引节俭了更多的存储空间,但查找起来须要耗费更多的工夫。
总结:
Kafka高效文件存储设计特点:
Kafka把topic中一个parition大文件分成多个小文件段,通过多个小文件段,就容易定期革除或删除曾经生产完文件,缩小磁盘占用。
通过索引信息能够疾速定位message和确定response的最大大小。
通过index元数据全副映射到memory,能够防止segment file的IO磁盘操作。
通过索引文件稠密存储,能够大幅升高index文件元数据占用空间大小。