架构师经典总结:为啥零拷贝可以提升Kafka性能?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了架构师经典总结:为啥零拷贝可以提升Kafka性能?相关的知识,希望对你有一定的参考价值。

参考技术A

计算机系统是由“硬件”和“软件”两大部分组成,计算机硬件包括一个或多个处理器(CPU)、内存、键盘、显示器、磁盘、I/O接口以及其他一些外围设备比如打印机,绘图仪等等。 总之,计算机硬件部分是一个由多种电子和机械设备组成的硬件系统。

为了让人方便正确使用这些设备,就需要编写若干程序来管理这些设备,正是这些程序组成了计算机的软件系统。软件也可以分为两大类:系统软件和应用软件。人们首先直接在硬件上加载一层程序,用它来管理整个计算机硬件设备以及一些软件信息资源,同时还为用户提供开发应用程序的环境,这就是操作系统软件和实用软件。应用软件是在操作系统支持下,为实现用户要求而编制的各种应用程序。

CPU、内存和I/O接口组成的主设备通常称为主机,把没有加载操作系统的主机叫做裸机。裸机与操作系统软件的接口是由CPU的指令系统和厂商提供的系统Bios组成。

由于操作系统向用户隐藏了系统使用的硬件设备,因此操作系统要为它上面的应用系统软件提供一组命令或系统调用接口供用户程序使用。比如我们需要使用磁盘,可以通过系统命名或系统调用来间接完成,而不需要亲自手动编写一个磁盘设备驱动程序。因此对于用户来说,当计算机加载操作系统后,用户不直接与计算机硬件打交道,而是利用操作系统提供的命令和功能区使用计算机。

由于操作系统处于硬件和软件的中央位置,因此很早就有人把操作系统成为计算机系统软件的核心,简称 核心 内核

内核态和用户态

从系统安全和保护的角度出发,在进行计算机体系结构设计时,处理机的执行模式一般设定为两种:分别称为内核模式(内核态)和用户模式(用户态)。当处理机处于内核模式执行时,意味着系统除了可以执行一般指令外,还可以执行特权指令,即可以执行访问各种控制寄存器的指令、I/O指令以及程序状态字。

当处理机处于用户模式执行时,只能执行一般指令,而不允许执行特权指令。这样做可以保护核心代码不受用户程序有意和无意的攻击。 显然,处理机在运行期间需要在内核模式和用户模式之前进行切换。

零拷贝

Kafka使用零拷贝(Zero-Copy)技术来提供它的性能,所谓的零拷贝是指将数据直接从磁盘文件复制到网卡设备中,而不需要经由应用程序之手,减少了内核和用户模式之间的上下文切换,零拷贝技术通过DMA技术实现。

直接存储器存取方式(Direct Memory Access, DMA) DMA控制方式是以存储器为中心,在主存和I/O设备之间建立一条直接通路,在DMA控制器的控制下进行设备和主存之间的数据交换。这种方式只在传输开始和传输结束时才需要CPU的干预。它非常适用于高速设备与主存之间的成批数据传输。

我们看下下面这样的这样一个场景:

客户端在游览器中发起请求获取内容,到看到具体内容经历了什么?

首先,该请求经过解析后,通过系统调用由用户态转为核心态执行,在核心态由操作系统中的TCP/IP协议代码和网卡驱动程序控制网卡把请求发送到相应的网络上, 等待Web服务器相应。当服务器返回时,由网卡接受,并通过内核传送给客户程序。

在服务器端,内核通过网卡从网络上接受Web请求,并通过系统调用传递给Web服务器。Web服务器根据此服务请求执行相应的服务进程,并由内核把结果发送到网络上传送给用户。

从上图中可以看到如果服务器从准备数据到发送数据经历了下面4个过程。

从上面过程可以看出,数据是先从内核模式-->用户模式-->内核模式,浪费了2次复制过程:第一次是从内核模式复制到用户模式;第二次是从用户模式再复制回内核模式,而且在上面的过程中,内核和用户模式的上下文切换也是4次。

如果采用了零拷贝技术,那么应用程序就可以直接请求内核把磁盘中的数据传输给Socket.

零拷贝技术通过DMA技术将文件内容复制到内核模式下的Read Buffer中。不过没有数据被复制到Socket Buffer,只有包含数据的位置和长度的信息的文件描述符被加到Socket Buffer中。DMA引擎直接将数据从内核模式中传递到网卡设备。这里上下文切换变成了2次,也只经历了2次复制过程就从磁盘中传送出去了。

Linux零拷贝原理

前言

大白话解释,零拷贝就是没有把数据从一个存储区域拷贝到另一个存储区域。但是没有数据的复制,怎么可能实现数据的传输呢?其实我们在java NIO、netty、kafka遇到的零拷贝,并不是不复制数据,而是减少不必要的数据拷贝次数,从而提升代码性能

  • 零拷贝的好处
  • 内核空间和用户空间
  • 缓冲区和虚拟内存
  • 传统的 I/O
  • mmap+write 实现的零拷贝
  • sendfile 实现的零拷贝
  • 带有DMA收集拷贝功能的sendfile实现的零拷贝
  • java提供的零拷贝方式

零拷贝的好处

  • 减少或避免不必要的CPU数据拷贝,从而释放CPU去执行其他任务
  • 零拷贝机制能减少用户空间和操作系统内核空间的上下文切换
  • 减少内存的占用

内核空间和用户空间

  • 内核空间:Linux自身使用的空间;主要提供进程调度、内存分配、连接硬件资源等功能
  • 用户空间:提供给各个程序进程的空间;用户空间不具有访问内核空间资源的权限,如果应用程序需要使用到内核空间的资源,则需要通过系统调用来完成:从用户空间切换到内核空间,完成相关操作后再从内核空间切换回用户空间

缓冲区和虚拟内存

  • 直接内存访问(Direct Memory Access)(DMA)
    • 直接内存访问:DMA允许外设设备和内存之间直接进行IO数据传输,其过程不需要CPU的参与 

  • 缓存区 是所有I/O的基础,I/O 无非就是把数据移进或移出缓冲区
    • 进程发起read请求,内核先检查内核空间缓存区是否存在进程所需数据,如果已经存在,则直接copy数据到进程的内存区。如果没有,系统则向磁盘请求数据,通过DMA写入内核的read缓存区,接着再将内核缓存区数据copy到进程的内存区
    • 进程发起write请求,则是把进程的内存区数据copy到内核的write缓存区,然后再通过DMA把内核缓存区数据刷回磁盘或者网卡中
  • 虚拟内存:现代操作系统都使用虚拟内存,有如下两个好处
    • 多个虚拟地址可以指向同一个物理内存地址
    • 虚拟内存空间可大于实际可用的物理地址
  • 利用第一点特性可以把内核空间地址和用户空间的虚拟地址映射到同一个物理地址,这样DMA就可以填充(读写)对内核和用户空间进程同时可见的缓冲区了;大致如下

传统的 I/O

读取一个我磁盘文件,并发送到远程服务

  • 1)发出read系统调用,会导致用户空间到内核空间的上下文切换,然后再通过DMA将文件中的数据从磁盘上读取到内核空间缓冲区
  • 2)接着将内核空间缓冲区的数据拷贝到用户空间进程内存,然后read系统调用返回。而系统调用的返回又会导致一次内核空间到用户空间的上下文切换
  • 3)write系统调用,则再次导致用户空间到内核空间的上下文切换,将用户空间的进程里的内存数据复制到内核空间的socket缓冲区(也是内核缓冲区,不过是给socket使用的),然后write系统调用返回,再次触发上下文切换
  • 4)至于socket缓冲区到网卡的数据传输则是独立异步的过程,也就是说write系统调用的返回并不保证数据被传输到网卡

「一共有四次用户空间与内核空间的上下文切换,四次数据copy,分别是两次CPU数据复制,两次DMA数据复制」

mmap+write实现的零拷贝

1)发出mmap系统调用,导致用户空间到内核空间的上下文切换。然后通过DMA引擎将磁盘中的数据复制到内核缓冲区;

2)mmap系统调用返回,导致内核空间到用户空间的上下文切换;

3)这里不需要将数据从内核空间复制到用户空间,因为用户空间和内核空间共享了这个缓冲区;

4)发出wrote系统调用,导致用户空间到内核空间的上下文切换。将数据从内核空间缓冲区复制到内核空间socket缓冲区;write系统调用返回,导致内核空间到用户空间的上下文切换;

5)DMA引擎异步的将socket缓冲区的数据复制到网卡。

「通过mmap实现的零拷贝I/O进行了4次用户空间与内核空间的上下文切换,以及3次数据拷贝;其中3次数据拷贝中包括了2次DMA拷贝和1次CPU拷贝」

sendfile实现的零拷贝

sendfile()是作用于数据拷贝在两个文件描述符之间的操作函数.这个拷贝操作是内核中操作的,所以称为"零拷贝"。

1)发出sendfile系统调用后,导致用户空间到内核空间的上下文切换,然后通过DMA引擎将磁盘文件中的内容复制到内核空间缓冲区,接着再将数据从内核空间缓冲区复制到socket相关的缓冲区;

2)sendfile系统调用返回,导致内核空间到用户空间的上下文切换,DMA异步将内核空间socket缓冲区中的数据传递到网卡

「通过sendfile实现的零拷贝I/O使用了2次用户空间与内核空间的上下文切换,以及3次数据的拷贝,其中3次数据拷贝中包括了2次DMA拷贝和1次CPU拷贝」

带有DMA收集拷贝功能的sendfile实现的零拷贝

  • 从Linux 2.4版本开始,操作系统提供scatter和gather的SG-DMA方式,直接从内核空间缓冲区中将数据读取到网卡,无需将内核空间缓冲区的数据再复制一份到socket缓冲区

  • 1)发出sendfile系统调用,导致用户空间到内核空间的上下文切换。通过DMA引擎将磁盘文件中的内容复制到内核空间缓冲区
  • 2)这里没把数据复制到socket缓冲区;取而代之的是,相应的描述符信息被复制到socket缓冲区。该描述符包含了两种的信息:A)内核缓冲区的内存地址、B)内核缓冲区的偏移量
  • 3)sendfile系统调用返回,导致内核空间到用户空间的上下文切换。DMA根据socket缓冲区的描述符提供的地址和偏移量直接将内核缓冲区中的数据复制到网卡

「带有DMA收集拷贝功能的sendfile实现的I/O使用了2次用户空间与内核空间的上下文切换,以及2次数据的拷贝,而且这2次的数据拷贝都是非CPU拷贝。这样一来我们就实现了最理想的零拷贝I/O传输了,不需要任何一次的CPU拷贝,以及最少的上下文切换」

本文转自 https://zhuanlan.zhihu.com/p/268713849

以上是关于架构师经典总结:为啥零拷贝可以提升Kafka性能?的主要内容,如果未能解决你的问题,请参考以下文章

深入探秘 NettyKafka 中的零拷贝技术!

NettyKafka中的零拷贝技术到底有多牛?

吃透Kafka二:kafka高性能之顺序IO页缓存零拷贝

吃透Kafka二:kafka高性能之顺序IO页缓存零拷贝

Kafka架构高性能和高可用性分析

Linux零拷贝原理