kafka处理快速的原因

2023-11-17

生产者分析

生产者(producer)是负责向Kafka提交数据的,我们先分析这一部分。Kafka会把收到的消息都写入到硬盘中,它绝对不会丢失数据。为了优化写入速度Kafka采用了两个技术, 顺序写入 和 MMFile。

  1. 顺序写入: 因为硬盘是机械结构,每次读写都会寻址->写入,其中寻址是一个“机械动作”,它是最耗时的。所以硬盘最“讨厌”随机I/O,最喜欢顺序I/O。为了提高读写硬盘的速度,Kafka就是使用顺序I/O。每一个Partition其实都是一个文件 ,收到消息后Kafka会把数据插入到文件末尾(虚框部分)。这种方法有一个缺陷—— 没有办法删除数据 ,所以Kafka是不会删除数据的,它会把所有的数据都保留下来,每个消费者(Consumer)对每个Topic都有一个offset用来表示 读取到了第几条数据 。如果不删除硬盘肯定会被撑满,所以Kakfa提供了两种策略来删除数据。一是基于时间,二是基于partition文件大小。具体配置可以参看它的配置文档。从分区读取数据的时候也是按顺序读取的,避免了随机读取。
  2. mmap:即便是顺序写入硬盘,硬盘的访问速度还是不可能追上内存。所以Kafka的数据并不是实时的写入硬盘 ,它充分利用了现代操作系统 分页存储 来利用内存提高I/O效率。Memory Mapped Files(后面简称mmap)也被翻译成 内存映射文件 ,在64位操作系统中一般可以表示20G的数据文件,它的工作原理是直接利用操作系统的Page来实现文件到物理内存的直接映射。完成映射之后你对物理内存的操作会被同步到硬盘上(操作系统在适当的时候)。内存映射文件的作用是使一个磁盘文件与存储空间中的一个缓冲区建立映射关系,然后当从缓冲区中取数据,就相当于读文件中的相应字节;而将数据存入缓冲区,就相当于写文件中的相应字节。这样就可以不使用read和write直接执行I/O了。

    在这里插入图片描述

消费者分析

  1. 零拷贝发送消费消息, Kafka把所有的消息都存放在一个一个的文件中, 当消费者需要数据的时候Kafka直接把“文件”发送给消费者 。这就是秘诀所在,比如: 10W的消息组合在一起是10MB的数据量,然后Kafka用类似于发文件的方式直接扔出去了,如果消费者和生产者之间的网络非常好,10MB可能只需要1s。所以答案是——10W的TPS,Kafka每秒钟处理了10W条消息。
  • 可能你说:不可能把整个文件发出去吧?里面还有一些不需要的消息呢?是的,Kafka作为一个“高级作弊分子”自然要把作弊做的有逼格。Zero Copy对应的是sendfile这个函数(以Linux为例),而sendfile的工作原理呢?
    1)、系统调用 sendfile() 通过 DMA 把硬盘数据拷贝到 kernel buffer,然后数据被 kernel 直接拷贝到另外一个与 socket 相关的 kernel buffer。这里没有 用户态和核心态 之间的切换,在内核中直接完成了从一个 buffer 到另一个 buffer 的拷贝。
    2)、DMA 把数据从 kernel buffer 直接拷贝给协议栈,没有切换,也不需要数据从用户态和核心态,因为数据就在 kernel 里。
  • Kafka是用mmap作为文件生产写入方式的,它就是一个文件句柄,所以直接把它传给sendfile进行消费;偏移也好解决,用户会自己保持这个offset,每次请求都会发送这个offset。(也可以放在zookeeper中);数据量更容易解决了,如果消费者想要更快,就全部扔给消费者。如果这样做一般情况下消费者肯定直接就被 压死了 ;所以Kafka提供了的两种方式——Push,我全部扔给你了,你死了不管我的事情;Pull,好吧你告诉我你需要多少个,我给你多少个。Kafka速度的秘诀在于,它把所有的消息都变成一个批量的文件,并且进行合理的批量压缩,减少网络IO损耗。通过mmap提高I/O速度,写入数据的时候由于单个Partion是末尾添加所以速度最优;读取数据的时候配合sendfile直接暴力输出。
  1. Kafka高效文件存储设计特点:Kafka把topic中一个parition大文件分成多个小文件段,通过多个小文件段,就容易定期清除或删除已经消费完文件,减少磁盘占用。Kafka的Message存储采用了分区(partition),分段(LogSegment)和稀疏索引这几个手段来达到了高效性。Kafka解决查询效率的手段之一是将数据文件分段,比如有100条Message,它们的offset是从0到99。假设将数据文件分成5段,第一段为0-19,第二段为20-39,以此类推,每段放在一个单独的数据文件里面,数据文件以该段中最小的offset命名。这样在查找指定offset的Message的时候,用二分查找就可以定位到该Message在哪个段中。

    在这里插入图片描述
  • 通过索引信息可以快速定位message和确定response的最大大小。
    通过index元数据全部映射到memory,可以避免segment file的IO磁盘操作。
    通过索引文件稀疏存储,可以大幅降低index文件元数据占用空间大小。
    比如:要查找绝对offset为7的Message:
    1)、首先是用二分查找确定它是在哪个LogSegment中,自然是在第一个Segment中。
    2)、打开这个Segment的index文件,也是用二分查找找到offset小于或者等于指定offset的索引条目中最大的那个offset。自然offset为6的那个索引是我们要找的,通过索引文件我们知道offset为6的Message在数据文件中的位置为9807。
    3)、打开数据文件,从位置为9807的那个地方开始顺序扫描直到找到offset为7的那条Message。这套机制是建立在offset是有序的。索引文件被映射到内存中,所以查找的速度还是很快的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

kafka处理快速的原因 的相关文章

  • k8s笔记25--k8s 跨主机网络flannel

    k8s笔记25 k8s 跨主机网络flannel 简介 不同机器上网络设备区别 flannel 网络常见三大后端模式 UDP VXLAN host gw 如何查看集群用哪种网络模式 阿里云flannel容器网络 alloc 参考文档 简介

随机推荐