有人说:他曾经在一台配置好的机器上对Kafka进行性能压力测试。压测结果显示,单个Kafka节点的极限处理能力接近每秒2000万条消息,吞吐量达到每秒600MB。那么为什么卡夫卡这么快?如何实现这种高性能?本文主要从生产端、Server端、Broker、Consumer端这三个角度来分析首先看生产端发送的消息。Kafka做了哪些优化?(1)生产端的Producer我们先回顾一下Producer发送消息的过程:首先,指定将消息发送到哪个Topic。选择一个topicpartition分区,默认是roundrobin进行负载均衡。也可以指定一个partitionkey,根据key的hash值分布到指定的partition。您还可以自定义分区以实现分区策略。找到该分区的领导分区。与主机上Broker的套接字建立通信。以Kafka自定义协议格式发送请求(包括携带消息和批量消息)。当你专注于发送消息时,你会发现这两点:批量消息和自定义协议格式。批量发送:减少服务器代理处理的请求数量,从而提高整体处理能力。当调用send()方法时,消息不会立即发送,而是会缓存起来,缓存中的消息会在合适的时候分成一批数据,分批发送给服务端Broker。自定义协议格式:序列化和压缩格式都可以减少数据量,从而节省网络资源消耗。各种压缩算法对比:吞吐量方面:LZ4>Snappy>zstd和GZIP压缩比:zstd>LZ4>GZIP>Snappy(2)服务器端Broker的高性能主要体现在这三个方面:PageCache缓存Kafka文件布局和磁盘文件顺序写入零拷贝sendfile:加速消费过程。下面我们就来说说吧。1)PageCache加速消息读写使用PageCache主要可以带来以下好处:写入文件时:操作系统会先将数据写入内存中的PageCache,然后再批量写入磁盘,从而减少磁盘IO开销。读取文件时:也从PageCache中读取数据。如果消息刚写入服务器,就会被消费。根据“先清除最近最少使用的页面”的LRU策略,读取时,命中刚刚写入的PageCache的概率会很高。2)Kafka的文件布局和磁盘文件的写入顺序如下图所示:主要特点是:文件的组织方式是“topic+partition”,每个topic可以创建多个partition,每个partition包含单独的文件文件夹。Kafka在分区级别实现了文件顺序写入:即多个文件同时写入,可以更好的发挥磁盘IO的性能。与RocketMQ相比:RocketMQ在写消息的时候追求极致的顺序写。无论主题如何,所有消息都按顺序写入提交日志文件。主题和分区数量的增加不会影响书写顺序。缺点:Kafka在写入消息时的IO性能会随着topic和partition数量的增加先升高后降低。所以在使用Kafka的时候,要注意主题和分区的数量。3)零拷贝sendfile:加速消费过程当不使用零拷贝技术读取数据时:流程如下:消费端Consumer:请求KafkaBroker拉取消息KafkaBroker从OSCache中读取消息到应用程序的内存空间:如果OSCache中有消息,则直接读取。如果OSCache中没有消息,就会从磁盘中读取,然后通过网卡通过socket发送给消费者。当使用零拷贝技术读取数据时:Kafka可以使用零拷贝技术将拷贝数减一,将数据直接从PageCache拷贝到Socketbuffer中。这避免了将数据复制到用户内存空间。DMA控制器直接完成数据拷贝,无需CPU参与,速度更快。(3)Consumer端Consumer只从Leader分区批量拉取消息。为了提高消费速度,必须有多个消费者并行消费。Kafka允许创建消费者组(唯一标识group.id),同一个消费者组中的消费者一起消费数据。举个栗子:有两台KafkaBrokers,也就是有2台机器有一个topic:TOPICA,有3个分区(0,1,2)如上图,例子4中的情况:group。id=1,有一个消费者:这个消费者需要处理所有数据,即3个分区的数据。group.id=2,有两个消费者:消费者1需要处理2个partition的数据,consumer2需要处理1个partition的数据group.id=3,有3个消费者:消费者个数和partition的number相等,每个consumer处理一个partitiongroup.id=4,有四个consumer:consumer数量>partition数量,第四个consumer会空闲
