kafka为什么这么快?

下面从数据写入和读取两方面分析,为什么Kafka速度这么快。

一、写入数据

1. 利用 Partition 实现并行处理

我们都知道 Kafka 是一个 Pub-Sub 的消息系统,无论是发布还是订阅,都要指定 Topic。

Topic 只是一个逻辑的概念。每个 Topic 都包含一个或多个 Partition,不同 Partition 可位于不同节点。

一方面,由于不同 Partition 可位于不同机器,因此可以充分利用集群优势,实现机器间的并行处理。另一方面,由于 Partition 在物理上对应一个文件夹,即使多个 Partition 位于同一个节点,也可通过配置让同一节点上的不同 Partition 置于不同的磁盘上,从而实现磁盘间的并行处理,充分发挥多磁盘的优势。

能并行处理,速度肯定会有提升,多个工人肯定比一个工人干的快。

2. 顺序写磁盘(避免了随机IO)

图片

图片来源:kafka.apache.org

Kafka 中每个分区是一个有序的,不可变的消息序列,新的消息不断追加到 partition 的末尾,这个就是顺序写。

每个消费者对每个topic都有一个offset用来表示读取到了第几条记录。

通过客户端提交offset的方式来记录 每个消费者读到哪条记录了,Kafka的Broker完全无视这个东西的存在;一般情况下SDK会把它保存到Zookeeper里面,所以需要给Consumer提供zookeeper的地址。

如果不删除硬盘肯定会被撑满,所以Kakfa提供了两种策略来删除数据:

  • 一是基于时间;
  • 二是基于partition文件大小。

先介绍一下零拷贝技术

零拷贝技术指在计算机执行操作时,CPU不需要先将数据从一个内存区域复制到另一个内存区域,从而可以减少上小文切换以及CPU拷贝事件。它的作用是在数据报从网络设备到用户程序传递的过程中,减少数据拷贝次数,减少系统调用,实现CPU的零参与,彻底消除CPU在这方面的负载 目前零拷贝技术主要有三种类型

  • 直接I/O:数据直接跨过内核,在用户地址空间与I/O设备之间传递,内核只是进行必要的虚拟存储配置等辅助工作;

  • 避免内核和用户空间之间的数据拷贝:当应用程序不需要对数据进行访问时,则可以避免将数据从内核空间拷贝到用户空间

    • mmap
    • sendfile
    • splice && tee
    • sockmap
  • copy on write:写时拷贝技术,数据不需要提前拷贝,而是当需要修改的时候再进行部分拷贝。

3.利用零拷贝技术之Memory Mapped Files (网络数据持久化到磁盘 (Producer 到 Broker))

传统模式下,数据从网络传输到文件需要 4 次数据拷贝、4 次上下文切换和两次系统调用。

data = socket.read()// 读取网络数据 
File file = new File() 
file.write(data)// 持久化到磁盘 
file.flush()

这一过程实际上发生了四次数据拷贝:

  1. 首先通过 DMA copy 将网络数据拷贝到内核态 Socket Buffer
  2. 然后应用程序将内核态 Buffer 数据读入用户态(CPU copy)
  3. 接着用户程序将用户态 Buffer 再拷贝到内核态(CPU copy)
  4. 最后通过 DMA copy 将数据拷贝到磁盘文件

DMA(Direct Memory Access):直接存储器访问。DMA 是一种无需 CPU 的参与,让外设和系统内存之间进行双向数据传输的硬件机制。使用 DMA 可以使系统 CPU 从实际的 I/O 数据传输过程中摆脱出来,从而大大提高系统的吞吐率。

同时,还伴随着四次上下文切换,如下图所示

图片

Memory Mapped Files(后面简称mmap)也被翻译成 内存映射文件

使用 mmap 的目的是将内核中读缓冲区(read buffer)的地址与用户空间的缓冲区(user buffer)进行映射。从而实现内核缓冲区与应用程序内存的共享,省去了将数据从内核读缓冲区(read buffer)拷贝到用户缓冲区(user buffer)的过程

它的工作原理是直接利用操作系统的 Page 来实现文件到物理内存的直接映射。完成映射之后你对物理内存的操作会被同步到硬盘上。使用这种方式可以获取很大的 I/O 提升,省去了用户空间到内核空间复制的开销。

对于 kafka 来说,Producer 生产的数据存到 broker,这个过程读取到 socket buffer 的网络数据,其实可以直接在内核空间完成落盘。并没有必要将 socket buffer 的网络数据,读取到应用进程缓冲区;在这里应用进程缓冲区其实就是 broker,broker 收到生产者的数据,就是为了持久化。

使用这种方式可以获取很大的I/O提升,省去了用户空间到内核空间复制的开销(调用文件的read会把数据先放到内核空间的内存中,然后再复制到用户空间的内存中。)

但也有一个很明显的缺陷——不可靠,写到mmap中的数据并没有被真正的写到硬盘,操作系统会在程序主动调用flush的时候才把数据真正的写到硬盘。

Kafka提供了一个参数——producer.type来控制是不是主动flush,如果Kafka写入到mmap之后就立即flush然后再返回Producer叫 同步 (sync);写入mmap之后立即返回Producer不调用flush叫异步 (async)。

图片

二、读取数据(磁盘文件通过网络发送(Broker 到 Consumer)

1.通过senfile实现零拷贝

Kafka在读取磁盘时做了哪些优化?

传统方式实现:先读取磁盘、再用 socket 发送,实际也是进过四次 copy

buffer = File.read 
Socket.send(buffer)

这一过程可以类比上边的生产消息:

  1. 首先通过系统调用将文件数据读入到内核态 Buffer(DMA 拷贝)
  2. 然后应用程序将内存态 Buffer 数据读入到用户态 Buffer(CPU 拷贝)
  3. 接着用户程序通过 Socket 发送数据时将用户态 Buffer 数据拷贝到内核态 Buffer(CPU 拷贝)
  4. 最后通过 DMA 拷贝将数据拷贝到 NIC Buffer(网卡缓冲区)

Linux 2.4+ 内核通过 sendfile 系统调用,提供了零拷贝。数据通过 DMA 拷贝到内核态 Buffer 后,直接通过 DMA 拷贝到 NIC Buffer,无需 CPU 拷贝。这也是零拷贝这一说法的来源。除了减少数据拷贝外,因为整个读文件 - 网络发送由一个 sendfile 调用完成,整个过程只有两次上下文切换,因此大大提高了性能。

图片

三、数据压缩和批处理

在很多情况下,系统的瓶颈不是 CPU 或磁盘,而是网络IO。

因此,除了操作系统提供的低级批处理之外,Kafka 的客户端和 broker 还会在通过网络发送数据之前,在一个批处理中累积多条记录 (包括读和写)。记录的批处理分摊了网络往返的开销,使用了更大的数据包从而提高了带宽利用率。

Producer 可将数据压缩后发送给 broker,从而减少网络传输代价,目前支持的压缩算法有:Snappy、Gzip、LZ4。数据压缩一般都是和批处理配套使用来作为优化手段的。

总结:

kafka为何这么快可以从三方面入手

一方面是写入数据,也就是数据从Producer发到Broker保存起来

该方面的优化包括:

  • 1.利用partition实现并行处理 ,由于不同 Partition 可位于不同机器,因此可以充分利用集群优势,实现机器间的并行处理
  • 2.利用顺序写磁盘,避免了随机IO
  • 3.利用零拷贝技术中的Memory Mapped Files ,谜底是将内核空间缓冲区和用户进程缓冲区,进行映射,这样省去了数据在内核空间缓冲区到用户进程缓冲区之间的复制

第二个方面是:读取数据,也就是数据从Broker到Consumer

该方面的优化包括:

  • 通过sendfile来实现零拷贝 ,数据通过DMA从硬盘中拷贝到内核态缓冲区之后,直接DMA拷贝到NIC Buffer

第三个方面:网络传输方面

该方面的优化包括:

  • 记录的批处理分摊了网络往返的开销,使用了更大的数据包从而提高了带宽利用率,同时压缩后减少了传输到的代价

第四个方面:也就是Kafka是如何处理请求的

详见:

Kafka 请求是怎么被处理的

参考:

https://mp.weixin.qq.com/s/dbnpPEF0FBB5A5xH21OoeQ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值