跳至主要內容

Kafka高性能浅析

向往大约 3 分钟开源框架消息队列kafka

总览

Kafka高性能原因如下图所示:

image-20221031104424610

分析

页缓存

页缓存是操作系统实现的一种主要的磁盘缓存,以此用来减少对磁盘 I/O 的操作。具体来说,就是把磁盘中的数据缓存到内存中,把对磁盘的访问变为对内存的访问。Kafka 中大量使用了页缓存,这是 Kafka 实现高吞吐的重要因素之一。

顺序读写

首先顺序写盘的速度不仅比随机写盘的速度快,而且也比随机写内存的速度快。Kafka 在设计时采用了文件追加的方式来写入消息,即只能在日志文件的尾部追加新的消息,并且也不允许修改已写入的消息,这种方式属于典型的顺序写盘的操作,所以就算 Kafka使用磁盘作为存储介质,也能保持一个较高的吞吐量。

零拷贝

零拷贝是指将数据直接从磁盘文件复制到网卡设备中,而不需要经由应用程序之手。零拷贝大大提高了应用程序的性能,减少了内核和用户模式之间的上下文切换。对 Linux操作系统而言,零拷贝技术依赖于底层的 sendfile()方法实现。对应于 Java 语言,FileChannal.transferTo()方法的底层实现就是sendfile()方法。

以读取一个文件写入到Socket为例,看下正常读写和零拷贝之间的区别。

  • 正常读写

过程如下图所示:

  1. 文件中的内容被复制到了内核模式下的Read Buffer中
  2. CPU控制将内核模式数据复制到用户模式下
  3. 用户模式下的内容复制到内核模式下的Socket Buffer中
  4. 将内核模式下的Socket Buffer的数据复制到网卡设备中传送

从上面的过程来看,数据首先从内核模式复制到用户模式,然后又从用户模式复制到内核模式,需要4次内核模式和用户模式上下文的切换。

image-20221031105746398

  • 零拷贝

    采用了零拷贝技术,那么应用程序可以直接请求内核把磁盘中的数据传输给Socket。如下图所示:

    image-20221031110158965

​ 零拷贝技术通过DMA(Direct Memory Access)技术将文件内容复制到内核模式下的Read Buffer 中。不过没有数据被复制到 Socket Buffer,相反只有包含数据的位置和长度的信息的文件描述符被加到Socket Buffer中。DMA引擎直接将数据从内核模式中传递到网卡设备(协议引擎)。这里数据只经历了2次复制就从磁盘中传送出去了,并且上下文切换也变成了2次。零拷贝是针对内核模式而言的,数据在内核模式下实现了零拷贝。

高效的日志结构设计

请参考Kafka日志存储

批量传输

请参考 Kafka生产消费

分区并发

Kafka的Topic可以分成多个Partition,每个 Paritition类似于一个队列,保证数据有序。同一个Group下的不同 Consumer并发消费Paritition,分区实际上是调优 Kafka 并行度的最小单元,因此,可以说,每增加一Paritition 就增加了一个消费并发。