七 消息是怎样存储在Kafka集群上的

Kafka文档

1. Kafka集群用log和index文件来存储消息

例如00000.log里存放的就是从offset 0开始的消息,相应地,00000.index里存放的是特定offset的消息在00000.log文件中的地址。

而当00000.log文件大小达到某个特定值时,就会写入下一个文件,00078.log以及00078.index。里面存放的是最小位移为78的消息。

另外,索引采用的是稀疏索引,并没有对每一个offset都建立索引。

$ ls -l
total 40
-rw-r--r--  1 user  admin         0  3 27 15:09 00000000000000000000.index
-rw-r--r--  1 user  admin       224  3 27 15:09 00000000000000000000.log
-rw-r--r--  1 user  admin        12  3 27 15:09 00000000000000000000.timeindex
-rw-r--r--  1 user  admin  10485760  4  3 15:19 00000000000000000078.index
-rw-r--r--  1 user  admin       107  4  3 15:19 00000000000000000078.log
-rw-r--r--  1 user  admin        10  4  3 15:19 00000000000000000078.snapshot
-rw-r--r--  1 user  admin  10485756  4  3 15:19 00000000000000000078.timeindex

log文件大小是由kafka segment参数决定的。默认是1个G.

# The maximum size of a log segment file. When this size is reached a new log segment will be created.
log.segment.bytes=1073741824

2. Kafka写文件的方式(Kafka吞吐量大的部分原因)

2.1 页缓存

操作系统中,有机制将磁盘中的数据放入内存中,也就是页缓存。进程对页缓存读写,操作系统负责页缓存和磁盘之间的数据同步。

Kafka中大量使用了页缓存,大大提高了系统的吞吐量。

2.2 顺序写

Kafka写文件采用了追加的方式,顺序写入磁盘的。
磁盘内部写入的时候,分为随机写入,和顺序写入。随机写入需要磁盘的磁头不断变道,寻址,再进行写操作。变道寻址会占用不少时间。而顺序写入,基本上不用变道和寻址,省去了很多时间。
所以Kafka写磁盘效率很高。

2.3 零拷贝 (zero-copy)

另外,还采用了零拷贝技术。零拷贝指的是减少数据拷贝的次数。
主要体现在 接收生产者发送的数据,和 取出消息发送给消费者时。

  • 传统方式中,接收消息,存入磁盘,会发生几次数据拷贝:
    首先,从网盘拷贝到socket;
    再从内核态的socket拷贝到用户态的应用内存;
    接着从用户态的内存拷贝到内核态的read buffer;
    最后从read buffer拷贝到硬盘。

这个过程发生了4次数据拷贝,2次用户态和内核态之间的切换,都是开销很大的。


传统方式
  • 在kafka中,通过零拷贝,也就是直接在内核态,将数据直接从网卡传输到磁盘,不经过应用程序,也不用切换到用户态。大大提高了性能。

注:操作系统有一些核心的功能,涉及到底层的很多关键操作,是不能随便让哪个程序就能去做的。那么需要做这部分操作,就需要到内核态执行。
一般情况下,应用程序都是在用户态执行,它只需要一些普通的权限就可以了。当应用程序需要执行一些底层的操作时,就需要先切换到内核态,才有权限去做。
而切换时,需要通过很多操作来完成,例如堆栈的切换等,开销是比较大的。(用户态与内核态

3. Kafka的日志和index是什么时候写入的

Kafka的日志并不是实时写入磁盘的。消息先被写入页缓存,待操作系统统一进行刷盘,将页缓存写入磁盘。
另外,kafka也提供了强制间隔刷盘,以及同步刷盘的选项,可以通过参数来指定。但是同步刷盘并不推荐,因为它严重影响了性能。

那么间隔刷盘,消息会不会丢呢?kafka的多副本机制是可靠性的保证,那么单个replication如果突发断电等,数据丢失,有其他副本依然保存了数据。所以间隔刷盘,消息可靠性依然是有保证的。

4. 读取某个offset的消息

在kafka中,topic的某个partition的每个log文件作为log segment,是通过跳表来存储的。
当需要读取某个offset的消息时,先通过跳表来找到相应的log segment。通过index文件找到相应offset的地址,再去log segment中找到相应地址的消息。

5. Kafka集群中的log是怎样被清理的

log清理有两种机制,第一种是日志删除,一种是日志压缩。

5.1 日志删除

按一定的保留策略,直接删除某些log segment。

  • 时间
    segment所存储消息的时间大于特定值,则需要被删除。
  • 大小
    log segment的总大小大于特定值,则删除前面的segment。
  • offset
    若segment的下一个segment 偏移量小于起始偏移量,则删除此segment。

kafka有一个专门负责删除日志的任务,会周期性地扫描segment。符合删除条件的话,就将其标为 .deleted后缀,最后通过一个延迟任务统一删除。这个延迟时间可以通过参数来指定。

5.2 日志压缩

对于相同key的消息,只保留其最新消息。

**********

理解了kafka的消息存储,就了解kafka为什么吞吐量大了

  1. 消息格式本身经过了合理的设计,用到一些机制,例如存相对offset的方式,来减小消息长度。
  2. 虽然用磁盘存储,但是用到了页缓存、顺序写磁盘、零拷贝的技术,大大提高了读写速度。
  3. 有数据文件,和相应的索引文件,读取消息的效率也非常之高。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、前言 Kafka 对消息的存储和缓存严重依赖于磁盘文件系统。人们对于“磁盘速度慢”的普遍印象,使得人们对于持久...
    正义的杰克船长阅读 567评论 0 1
  • 1. kafka文件存储机制   Kafka中发布订阅的对象是topic,我们可以为每类数据创建一个topic,P...
    火山_6c7b阅读 650评论 0 0
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 126,281评论 2 7
  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 6,122评论 0 4