首页 > 编程知识 正文

kafka官网,kafka零拷贝技术

时间:2023-05-04 05:18:34 阅读:16823 作者:1047

链接: https://庄兰.智惠.com/p/78335525

为什么要让kafka成为存储层呢? 可以存储数据的MySQL、MongoDB、HDFS……

因为kafka数据是持久的、高速的。可靠性高,支持分散……

啥!用了磁盘,还速度快!!!

没错,肯德基是速度无敌的。 本文将探究kafka无敌性能背后的秘密。

首先有一个概念。 kafka高性能的背后,是多方面合作后的最终结果。 kafka高效地利用宏体系结构、分布式分区存储、ISR数据同步和“无孔”磁盘/操作系统的特性。 这些多方面的合作是肯德基成为性能之王的必然结果。

本文将从kafka的零拷贝开始,探讨如何高效地利用磁盘/操作系统的特性。

先说说零拷贝零拷贝不是不需要拷贝,而是减少不必要的拷贝次数。 通常在IO的读写中。

其实,零拷贝有广义和狭义之分,现在我们通常听到的零拷贝,包括上面的定义在内,减少不必要的拷贝次数也是广义的零拷贝。 其实知道那个就足够了。

我们知道减少不必要的复制次数是为了提高效率。 那个零拷贝之前,怎么样呢?

聊聊传统IO流程例如,读取文件并通过套接字发送

传统方法实现:

先读取,再发送,实际复制1~4次。

buffer=file.read socket.send (buffer ) 1,首次:将磁盘文件装入操作系统内核缓冲区;

2、第二次:将内核缓冲区的数据复制到APP的缓冲区;

3、步骤3 )将APP buffer中的数据复制到套接字网络并发送的缓冲器(属于OS内核缓冲器);

4、第4次:将socket buffer的数据、copy传递给网卡,从网卡进行网络传输。

在以往的方式中,由于读取磁盘文件并进行网络发送,所以4次数据复制非常复杂。 实际的IO读写需要IO中断,CPU必须对中断作出响应。 之后,引入了DMA来接管CPU的中断请求,但四次拷贝都存在“不必要的拷贝”。

如果重新审视传统的IO方法,就会发现实际上不需要第二个和第三个数据拷贝。 除了缓存数据并将其传输到套接字缓冲区之外,APP应用程序什么也不做。 相反,数据可以直接从读缓冲区传输到套接字缓冲区。

很明显,第二次和第三次数据拷贝实际上在这样的场景中没有任何作用,反而会带来开销。 这就是零拷贝的意思。

导入磁盘文件后,不进行其他处理,直接在网络上发送的场景。 如果需要以编程方式进一步处理读取到磁盘的数据,请考虑经过第二次和第三次数据复制后,APP应用程序需要在内存缓冲区中进行处理。

为什么Kafka这么快kafka无论是MQ还是存储层,都只是两个重要功能:将Producer生产的数据存储在broker中,以及Consumer从broker读取数据

1、网络数据到磁盘的永久化(从产品到中介) )。

2、通过网络发送磁盘文件(从中介到Consumer ) )。

以下,首先得出“kafka正在使用磁盘,速度还很快”的结论

1、序贯读写

磁盘的顺序读取或写入速度为400M/s,可发挥磁盘的最大速度。

读写、磁盘速度慢时为十几~几百k /秒。 这样就知道差别了。

kafka将来自Producer的数据依次追加到partition中,partition是一个文件,由此实现依次写入。

Consumer从broker读取数据时,带有偏移量,因此通过继续读取上次读取的位置,实现顺序读取。

顺序读写是kafka利用光盘特性的重要表现。

2、零拷贝sendfile(in,out ) ) )。

数据通过内核直接输入和输出,不需要复制到用户区域后再写入。

在将kafka数据写入磁盘之前,数据将写入进程的内存区域。

3、mmap文件映射

虚拟映射仅支持文件;

在进程的非堆内存中打开一个内存空间,并将其映射到操作系统内核空间中的一个内存。

kafka数据写入到该内存空间,但实际上映射到该内存和操作系统内核内存。 也就是说,被写入内核存储器空间,该内核空间、内核可以直接访问,直接落入磁盘。

其中,内核缓冲区中的数据必须表明flush可以完成磁盘丢弃。

让我们重点看看kafka的两个关键流程,以及如何利用两种零拷贝技术sendfile和mmap。

网络数据持久化到磁盘 (Producer 到 Broker)实现传统方式:

data=socket.read ()//读取网络数据的File file=new File ) (file.write ) ) /磁盘file.flush ) )持久化并先接收生产者

发来的消息,再落入磁盘。
实际会经过四次copy,如下图的四个箭头。

数据落盘通常都是非实时的,kafka生产者数据持久化也是如此。Kafka的数据并不是实时的写入硬盘,它充分利用了现代操作系统分页存储来利用内存提高I/O效率。

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

在此特殊场景下:接收来自socket buffer的网络数据,应用进程不需要中间处理、直接进行持久化时。——可以使用mmap内存文件映射。

Memory Mapped Files

简称mmap,简单描述其作用就是:将磁盘文件映射到内存, 用户通过修改内存就能修改磁盘文件。
它的工作原理是直接利用操作系统的Page来实现文件到物理内存的直接映射。完成映射之后你对物理内存的操作会被同步到硬盘上(操作系统在适当的时候)。

通过mmap,进程像读写硬盘一样读写内存(当然是虚拟机内存),也不必关心内存的大小有虚拟内存为我们兜底。
使用这种方式可以获取很大的I/O提升,省去了用户空间到内核空间复制的开销。

mmap也有一个很明显的缺陷——不可靠,写到mmap中的数据并没有被真正的写到硬盘,操作系统会在程序主动调用flush的时候才把数据真正的写到硬盘。Kafka提供了一个参数——producer.type来控制是不是主动flush;如果Kafka写入到mmap之后就立即flush然后再返回Producer叫同步(sync);写入mmap之后立即返回Producer不调用flush叫异步(async)。

Java NIO对文件映射的支持

Java NIO,提供了一个 MappedByteBuffer 类可以用来实现内存映射。
MappedByteBuffer只能通过调用FileChannel的map()取得,再没有其他方式。
FileChannel.map()是抽象方法,具体实现是在 FileChannelImpl.c 可自行查看JDK源码,其map0()方法就是调用了Linux内核的mmap的API。

使用 MappedByteBuffer类要注意的是:mmap的文件映射,在full gc时才会进行释放。当close时,需要手动清除内存映射文件,可以反射调用sun.misc.Cleaner方法。

磁盘文件通过网络发送(Broker 到 Consumer)

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

buffer = File.read Socket.send(buffer)

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

相比于文章开始,对传统IO 4步拷贝的分析,sendfile将第二次、第三次拷贝,一步完成。

其实这项零拷贝技术,直接从内核空间(DMA的)到内核空间(Socket的)、然后发送网卡。
应用的场景非常多,如Tomcat、Nginx、Apache等web服务器返回静态资源等,将数据用网络发送出去,都运用了sendfile。
简单理解 sendfile(in,out)就是,磁盘文件读取到操作系统内核缓冲区后、直接扔给网卡,发送网络数据。

Java NIO对sendfile的支持就是FileChannel.transferTo()/transferFrom()。
fileChannel.transferTo( position, count, socketChannel);
把磁盘文件读取OS内核缓冲区后的fileChannel,直接转给socketChannel发送;底层就是sendfile。消费者从broker读取数据,就是由此实现。

具体来看,Kafka 的数据传输通过 TransportLayer 来完成,其子类 PlaintextTransportLayer 通过Java NIO 的 FileChannel 的 transferTo 和 transferFrom 方法实现零拷贝。

@Overridepublic long transferFrom(FileChannel fileChannel, long position, long count) throws IOException { return fileChannel.transferTo(position, count, socketChannel);}

注: transferTo 和 transferFrom 并不保证一定能使用零拷贝。实际上是否能使用零拷贝与操作系统相关,如果操作系统提供 sendfile 这样的零拷贝系统调用,则这两个方法会通过这样的系统调用充分利用零拷贝的优势,否则并不能通过这两个方法本身实现零拷贝。

Kafka总结

总的来说Kafka快的原因:
1、partition顺序读写,充分利用磁盘特性,这是基础;
2、Producer生产的数据持久化到broker,采用mmap文件映射,实现顺序的快速写入;
3、Customer从broker读取数据,采用sendfile,将磁盘文件读到OS内核缓冲区后,直接转到socket buffer进行网络发送。

mmap 和 sendfile总结

1、都是Linux内核提供、实现零拷贝的API;
2、sendfile 是将读到内核空间的数据,转到socket buffer,进行网络发送;
3、mmap将磁盘文件映射到内存,支持读和写,对内存的操作会反映在磁盘文件上。
RocketMQ 在消费消息时,使用了 mmap。kafka 使用了 sendFile。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。