Kafka的高性能磁盘读写实现原理

一、概述

  • Kafka作为一个支持大数据量写入写出的消息队列,由于是基于Scala和Java实现的,而Scala和Java均需要在JVM上运行,所以如果是基于内存的方式,即JVM的堆来进行数据存储则需要开辟很大的堆来支持数据读写,从而会导致GC频繁影响性能。考虑到这些因素,kafka是使用磁盘而不是kafka服务器broker进程内存来进行数据存储,并且基于磁盘顺序读写和MMAP技术来实现高性能。

二、存储结构

目录与文件结构

  • 由之前的文章分析可知,kafka是通过主题和分区来对消息进行分类的,所以在磁盘存储结构方面也是基于分区来组织的,即每个目录存放一个分区的数据,目录名为“主题-分区号”,如mytopic这个主题包含两个分区,则对应的数据目录分别为:mytopic-0和my-topic-1,如下:

    ./kafka-topics.sh --create --topic mytopic --partitions 2 --zookeeper localhost:2181 --replication-factor 2
    
    xyzdeMacBook-Pro:bin xyz ./kafka-topics.sh --describe --topic mytopic --zookeeper localhost:2181
    Topic:mytopic   PartitionCount:2    ReplicationFactor:2 Configs:
        Topic: mytopic  Partition: 0    Leader: 2   Replicas: 2,1   Isr: 2,1
        Topic: mytopic  Partition: 1    Leader: 0   Replicas: 0,2   Isr: 0,2
    
  • 由于在本机存在3个brokers,对应的server.properties的broker.id分别为:0, 1, 2,所以通过--describe选项查看的mytopic的详细信息可知:
    mytopic的分区0是分区leader为broker2,同步副本为broker1和broker2;分区1的分区leader为broker0,同步副本为broker0和broker2。

  • 以上命令对应的主题mytopic存在两个分区和每个分区存在两个分区副本,其中broker0,broker1和broker2对应的数据目录在server.properties文件配置的log.dirs分别为;
    /tmp/kafka-logs,/tmp/kafka-logs2,/tmp/kafka-logs3。所以mytopic主题对应的两个分区在磁盘上的目录结构如下:

    xyzdeMacBook-Pro:bin xyz cd /tmp/kafka-logs
    xyzdeMacBook-Pro:kafka-logs xyz ls
    mytopic-1               recovery-point-offset-checkpoint    replication-offset-checkpoint
    
    xyzdeMacBook-Pro:kafka-logs xyz cd /tmp/kafka-logs2/
    xyzdeMacBook-Pro:kafka-logs2 xyz ls
    mytopic-0               recovery-point-offset-checkpoint    replication-offset-checkpoint
    
    xyzdeMacBook-Pro:kafka-logs2 xyz cd /tmp/kafka-logs3
    xyzdeMacBook-Pro:kafka-logs3 xyz ls
    mytopic-0               recovery-point-offset-checkpoint
    mytopic-1               replication-offset-checkpoint
    
    1. mytopic-0分区:在broker2对应的数据目录/tmp/kafka-logs3下面存在mytopic-0的主分区,broker1对应的数据目录/tmp/kafka-logs2存放mytopic-0的另外一个分区副本;
    2. mytopic-1分区:在broker0对应的数据目录/tmp/kafka-logs下面存放mytopic-1的主分区,broker2对应的数据目录/tmp/kafka-logs3存放mytopic-1的另外一个分区。

文件内容

  • kafka的数据文件是二进制格式的文件,因为二进制的文件大小相对于文本文件更小,所以可以减少数据传输,复制量,提高数据传输速度,节省网络带宽。

  • 在分区目录下面除了存在数据文件之外,还存在一个索引文件,索引文件的作用是加快在数据文件的检索速度,索引文件也是二进制文件,如下以index结尾的就是索引文件,以log结尾的就是数据文件:

    xyzdeMacBook-Pro:mytopic-1 xieyizun$ ls -allh
    total 0
    drwxr-xr-x  4 xieyizun  wheel   128B  4 27 09:56 .
    drwxr-xr-x  6 xieyizun  wheel   192B  4 27 20:26 ..
    -rw-r--r--  1 xieyizun  wheel    10M  4 27 09:56 00000000000000000000.index
    -rw-r--r--  1 xieyizun  wheel     0B  4 27 09:56 00000000000000000000.log
    
  • 整个分区的数据不是由一个数据文件存放的,而是由多个segments组成的,即上面看到的0000.log文件是其中一个segment文件,文件名是以该文件的第一个数据相对于该分区的全局offset命名的。每当segment文件达到一定的大小,则会创建一个新的segment文件,具体大小在server.properties配置:默认为1G。

    # The maximum size of a log segment file. When this size is reached a new log segment will be created.
    
    log.segment.bytes=1073741824
    
  • 而索引文件的文件内容也是offset的稀疏索引,从而在消费者消费消息时,broker根据消费者给定的offset,基于二分查找先在索引文件找到该offset对应的数据segment文件的位置,然后基于该位置(或往下)找到对应的数据。

  • 具体内容格式如图所示:


    在这里插入图片描述

三、消息写入

磁盘顺序写
  • 当broker接收到producer发送过来的消息时,需要根据消息的主题和分区信息,将该消息写入到该分区当前最后的segment文件中,文件的写入方式是追加写。
  • 由于是对segment文件追加写,故实现了对磁盘文件的顺序写,避免磁盘随机写时的磁盘寻道的开销,同时由于是追加写,故写入速度与磁盘文件大小无关,具体如图:


    在这里插入图片描述
页缓存PageCache
  • 虽然消息写入是磁盘顺序写入,没有磁盘寻道的开销,但是如果针对每条消息都执行一次磁盘写入,则也会造成大量的磁盘IO,影响性能。
  • 所以在消息写入方面,broker基于MMAP技术,即内存映射文件,将消息先写入到操作系统的页缓存中,由页缓存直接映射到磁盘文件,不需要在用户空间和内核空间直接拷贝消息,所以也可以认为消息传输是发送在内存中的。
  • 由于是先将消息写入到操作系统的页缓存,而页缓存数据刷新同步sync到磁盘文件是由操作系统来控制的,即操作系统通过一个内核后台线程,每5秒检查一次是否需要将页缓存数据同步到磁盘文件,如果超过指定时间或者超过指定大小则将页缓存数据同步到磁盘。所以如果在刷新到磁盘文件之前broker机器宕机了,则会导致页缓存的数据丢失。具体可以参考:Kafka消息的存储
  • 使用页缓存的另外一个好处是,如果重启了kafka服务端(这个服务重启,而不是机器重启),页缓存中的数据还是可以继续使用的。

四、消息读取

  • 消费者负责向broker发送从某个分区读取消费消息的请求,broker接收到消费者数据读取请求之后,根据消费者提供主题,分区与分区offset信息,找到给定的分区index和segment文件,然后通过二分查找定位到给定的数据记录,最后通过socket传输给消费者。

零拷贝读取

  • broker在从segment文件读取消息然后通过socket传输给消费者时,也是基于MMAP技术实现了零拷贝读取。
传统IO与socket传输
  • 对于传统的socket文件读取传输的过程为:
    1. 操作系统将磁盘文件数据读取到内核空间的页缓存;
    2. 应用通过系统调用将数据从内核空间读取到用户空间的缓存中;
    3. 应用通过系统调用将数据从用户空间的缓存回写到内核空间的socket缓冲区;
    4. 操作系统将内核空间的socket缓存区中的数据写到网卡硬件缓存中,以便将数据发送出去。
  • 所以一次socket文件读取传输涉及到两次系统调用和四次拷贝。具体如图所示:


    在这里插入图片描述
基于MMAP的零拷贝
  • 操作系统提供了sendfile系统调用来支持MMAP机制,即应用只需指定需要传输的磁盘文件句柄,然后通过sendfile系统实现磁盘文件读取和从socket传输出去,其中磁盘文件的读取和从socket传输出去都是通过sendfile系统调用在内核完成的,不需要在内核空间和用户空间进行数据拷贝,具体过程如下:

    1. 应用指定需要传输的文件句柄和调用sendfile系统调用;
    2. 操作系统在内核读取磁盘文件拷贝到页缓存;
    3. 操作系统在内核将页缓存内容拷贝到网卡硬件缓存。
  • 故整个过程涉及到一次sendfile系统调用,在内核态完成两次拷贝,在内核和用户空间之间不需要进行数据拷贝。具体过程如图所示:


    在这里插入图片描述
  • 所以kafka使用sendfile系统,具体为Java的senfile系统调用API: FileChannel的transferTo, transferFrom
    ,基于MMAP机制实现了磁盘文件内容的零拷贝传输。同时由于操作系统将磁盘文件内容加载到了内核页缓存,故消费者针对该磁盘文件的多次请求可以重复使用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,271评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,725评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,252评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,634评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,549评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,985评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,471评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,128评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,257评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,233评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,235评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,940评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,528评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,623评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,858评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,245评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,790评论 2 339

推荐阅读更多精彩内容