kafka的文件存储机制

2023-03-02  本文已影响0人  CoderInsight

(1) 概述

同一个topic下有多个不同的partition,每个partition为一个目录,partition命名的规则是topic的名称加上一个序号,序号从0开始。例如test分区,则会以如下方式存储:

test01
test02

每一个partition目录下的文件被平均切割成大小相等(默认一个文件是1G,可以手动去设置)的数据文件,每一个数据文件都被称为一个段(segment file),但每个段消息数量不一定相等,这种特性能够使得老的segment可以被快速清除。默认保留7天的数据。
每次满1G后,在写入到一个新的文件中。


1577524051165.png
    另外每个partition只需要支持顺序读写就可以。如上图所示:
首先00000000000000000000.log是最早产生的文件,该文件达到1G后又产生了新的 00000000000002025849.log 文件,新的数据会写入到这个新的文件里面。另外此时文件名的命令也是有规律可循的,2025849 说明前一个log文件中已经存储了 2025849-1 条记录。
    这个文件到达1G后,数据又会写入到下一个文件中。也就是说它只会往文件的末尾追加数据,这就是顺序写的过程,生产者只会对每一个partition做数据的追加(写操作)。

(2) 数据消费问题讨论

对于保证全局有序性、分区有序性的讨论(某一个分区有序,可以说是保证每个用户的局部有序)。

问题:如何保证消息消费的有序性呢?比如说生产者生产了0到100个商品,那么消费者在消费的时候按照0到100这个从小到大的顺序消费?

那么kafka如何保证这种有序性呢?
难度就在于,生产者生产出0到100这100条数据之后,通过一定的分组策略存储到broker的partition中的时候,
比如0到10这10条消息被存到了这个partition中,10到20这10条消息被存到了那个partition中,这样的话,消息在分组存到partition中的时候就已经被分组策略搞得无序了。

那么能否做到消费者在消费消息的时候全局有序呢?
遇到这个问题,我们可以回答,在大多数情况下是做不到全局有序的。但在某些情况下是可以做到的。比如我的partition只有一个,这种情况下是可以全局有序的。

那么可能有人又要问了,只有一个partition的话,哪里来的分布式呢?哪里来的负载均衡呢?
所以说,全局有序是一个伪命题!全局有序根本没有办法在kafka要实现的大数据的场景来做到。但是我们只能保证当前这个partition内部消息消费的有序性。

结论:一个partition中的数据是有序的吗?回答:间隔有序,不连续。

针对一个topic里面的数据,只能做到partition内部有序,不能做到全局有序。特别是加入消费者的场景后,如何保证消费者的消费的消息的全局有序性,
这是一个伪命题,只有在一种情况下才能保证消费的消息的全局有序性,那就是只有一个partition。

(3) Segment文件

    生产者生产的消息按照一定的分区策略被发送到topic中partition中,partition在磁盘上就是一个目录,该目录名是topic的名称加上一个序号,在这个partition目录下,有两类文件,一类是以log为后缀的文件,一类是以index为后缀的文件,每一个log文件和一个index文件相对应,这一对文件就是一个segment file,也就是一个段。
    其中的log文件就是数据文件,里面存放的就是消息,而index文件是索引文件,索引文件记录了元数据信息。log文件达到1个G后滚动重新生成新的log文件

(4) kafka如何快速查询数据

kafka.png
    上图的左半部分是索引文件,里面存储的是一对一对的key-value,其中key是消息在数据文件(对应的log文件)中的编号,比如“1,3,6,8……”,
    分别表示在log文件中的第1条消息、第3条消息、第6条消息、第8条消息……,那么为什么在index文件中这些编号不是连续的呢?
    这是因为index文件中并没有为数据文件中的每条消息都建立索引,而是采用了稀疏存储的方式,每隔一定字节的数据建立一条索引。
    这样避免了索引文件占用过多的空间,从而可以将索引文件保留在内存中。
但缺点是没有建立索引的Message也不能一次定位到其在数据文件的位置,从而需要做一次顺序扫描,但是这次顺序扫描的范围就很小了。

    其中以索引文件中元数据8,1686为例,其中8代表在右边log数据文件中从上到下第8个消息(在全局partiton表示第368777个消息),其中1686表示该消息的物理偏移地址(位置)为1686。
    
    要是读取offset=368777的消息,从00000000000000368769.log文件中的1686的位置进行读取,那么怎么知道何时读完本条消息,否则就读到下一条消息的内容了?
    
20170107212325100.png

参数说明:

关键字 解释说明
8 byte offset 在parition(分区)内的每条消息都有一个有序的id号,这个id号被称为偏移(offset),它可以唯一确定每条消息在parition(分区)内的位置。即offset表示partiion的第多少message
4 byte message size message大小
4 byte CRC32 用crc32校验message
1 byte “magic" 表示本次发布Kafka服务程序协议版本号
1 byte “attributes" 表示为独立版本、或标识压缩类型、或编码类型。
4 byte key length 表示key的长度,当key为-1时,K byte key字段不填
K byte key 可选
value bytes payload 表示实际消息数据。
    这个就需要涉及到消息的物理结构了,消息都具有固定的物理结构,包括:offset(8 Bytes)、消息体的大小(4 Bytes)、crc32(4 Bytes)、magic(1 Byte)、attributes(1 Byte)、key length(4 Bytes)、key(K Bytes)、payload(N Bytes)等等字段,可以确定一条消息的大小,即读取到哪里截止。

(5) kafka高效文件存储设计特点

上一篇下一篇

猜你喜欢

热点阅读