Title

kafka10- kafka为什么那么快

1零拷贝机制

零拷贝:零拷贝就是一种避免 CPU 将数据从一块存储拷贝到另外一块存储的技术,数据直接从磁盘文件复制到网卡设备中,而不需要经由应用程序之手 。零拷贝大大提高了应用程序的性能,减少了内核和用户模式之间的上下文切换 。

传统IO

比如:读取文件,socket发送

传统方式实现:先读取、再发送,实际经过1~4四次copy。

1、第一次:将磁盘文件,读取到操作系统内核缓冲区;

2、第二次:将内核缓冲区的数据,copy到application应用程序的buffer;

3、第三步:将application应用程序buffer中的数据,copy到socket网络发送缓冲区(属于操作系统 内核的缓冲区);

4、第四次:将socket buffer的数据,copy到网络协议栈,由网卡进行网络传输。

image-20210821203001205

实际上并不需要第二个和第三个数据副本。数据可以直接从读缓冲区传输到套接字缓冲区

kafka的两个过程:

 1、网络数据持久化到磁盘 (Producer 到 Broker) 
 2、磁盘文件通过网络发送(Broker 到 Consumer)

数据落盘通常都是非实时的,Kafka的数据并不是实时的写入硬盘,它充分利用了现代操作系统分 页存储来利用内存提高I/O效率

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

transferTo 和 transferFrom 并不保证一定能使用零拷贝,需要操作系统支持。 Linux 2.4+ 内核通过 sendfile 系统调用,提供了零拷贝。

2 页缓存

页缓存是操作系统实现的一种主要的磁盘缓存,以此用来减少对磁盘 I/O 的操作。

具体来说,就是把磁盘中的数据缓存到内存中,把对磁盘的访问变为对内存的访问。

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

Memory Mapped Files 简称mmap,简单描述其作用就是:将磁盘文件映射到内存, 用户通过修改内存就能修改磁盘文 件。

其的工作原理是直接利用操作系统的Page来实现磁盘文件到物理内存的直接映射。完成映射之后你 对物理内存的操作会被同步到硬盘上(操作系统在适当的时候)。

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.map()可自行查看JDK源码,其 map0()方法就是调用了Linux内核的mmap的API。

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

当一个进程准备读取磁盘上的文件内容时:

  1. 操作系统会先查看待读取的数据所在的页 (page)是否在页缓存(pagecache)中,如果存在(命中)则直接返回数据,从而避免了对物理磁盘的 I/O 操作;
  2. 如果没有命中,则操作系统会向磁盘发起读取请求并将读取的数据页存入页缓存,之后再将数 据返回给进程

如果一个进程需要将数据写入磁盘:

  1. 操作系统也会检测数据对应的页是否在页缓存中,如果不存在,则会先在页缓存中添加相应的 页,最后将数据写入对应的页。
  2. 被修改过后的页也就变成了脏页,操作系统会在合适的时间把脏页中的数据写入磁盘,以保持数据的一致性。

Kafka中大量使用了页缓存,这是 Kafka 实现高吞吐的重要因素之一。 消息先被写入页缓存,由操作系统负责刷盘任务。

3 顺序写入

Kafka 在设计时采用了文件追加的方式来写入消息,即只能在日志文件的尾部追加新的消 息,并且也不允许修改已写入的消息,这种方式属于典型的顺序写盘的操作,所以就算 Kafka 使用磁盘作为存储介质,也能承载非常大的吞吐量。

避免磁盘的寻址开销

mmap和sendfile:

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

Kafka速度快是因为:

1. partition顺序读写,充分利用磁盘特性,这是基础;
2. Producer生产的数据持久化到broker,采用mmap文件映射,实现顺序的快速写入;
3. Customer从broker读取数据,采用sendfile,将磁盘文件读到OS内核缓冲区后,直接转到socket buffer进行网络发送。
posted @ 2021-08-21 23:40  apeGcWell  阅读(44)  评论(0编辑  收藏  举报