当前位置:首页 > 问答 > 正文

Kafka到底怎么做到那么快,吞吐量高得让人怀疑真实性

根据马丁·克莱普曼(Martin Kleppmann)在《设计数据密集型应用》一书中的分析,以及卡夫卡官方文档和杰伊·克雷普斯(Jay Kreps,卡夫卡联合创始人)等人的技术分享,卡夫卡之所以能达到极高的吞吐量,让人感觉快得不真实,并非依赖某种单一的“黑科技”,而是通过一系列精心设计的、相互配合的架构选择,将“顺序读写”这个传统机械硬盘的优势发挥到极致,并尽可能减少不必要的开销。

最核心的一点是,卡夫卡彻底拥抱了顺序读写的巨大优势,传统的机械硬盘,随机读写的速度可能只有每秒几百次,但顺序读写的吞吐量可以达到每秒几百兆字节,两者性能相差数千倍,即使是固态硬盘(SSD),顺序读写的性能也远优于随机读写,卡夫卡的消息是持久化到磁盘日志文件里的,但它不是来一条消息就随机写一次磁盘,相反,它将消息简单地、按照到达的顺序追加(Append)到文件的末尾,这种操作是纯粹的、连续的顺序写操作,是硬盘最擅长的工作模式,速度极快,同样,消费者读取消息时,也是从文件的开头或某个偏移量开始,进行大块的顺序读取,这同样非常高效,杰伊·克雷普斯曾多次强调,这种“简单的日志”结构是卡夫卡高性能和耐久性的基石。

Kafka到底怎么做到那么快,吞吐量高得让人怀疑真实性

为了最大化顺序读写的效率,卡夫卡在I/O(输入/输出)方面做了大量优化,主要体现在批处理和压缩上,如果生产者每发送一条小消息,卡夫卡就把它写入磁盘一次,那么即使这是顺序写,频繁的磁盘操作也会成为瓶颈,卡夫卡不会立即写入每一条消息,它会在内存中积累一批消息,然后在合适的时机(比如达到一定数量、或经过一定时间间隔)一次性将整批消息顺序写入磁盘,这种做法将多次小的磁盘I/O操作合并为一次大的、高效的顺序I/O操作,极大地提高了磁盘的利用率,同样,在从生产者接收消息和向消费者发送消息时,卡夫卡也使用批处理来减少网络往返次数,卡夫卡支持对整批消息进行压缩(如gzip、Snappy、LZ4),在网络传输和磁盘存储上都能节省大量带宽和空间,从而间接提升了吞吐量。

第三,卡夫卡采用了零拷贝技术来优化数据传输路径,在普通的数据读取和发送过程中,数据需要在内核态的页面缓存和用户态的应用内存之间来回拷贝多次,最后还要拷贝到网卡缓冲区,这个过程会消耗宝贵的CPU资源,卡夫卡利用了现代操作系统提供的sendfile系统调用,当消费者请求数据时,卡夫卡不需要将数据先读入自己的应用内存,而是直接指示操作系统将磁盘文件(确切地说是页面缓存中的文件数据)中的数据,通过DMA(直接内存访问)方式直接发送到网络接口,这样就省去了内核态和用户态之间的多次数据拷贝,使得数据几乎不经过应用程序,直接从一个文件描述符传输到另一个文件描述符,这个技术极大地降低了CPU的负担,使得卡夫卡在高速网络环境下也能轻松地将磁盘上的数据推送出去。

Kafka到底怎么做到那么快,吞吐量高得让人怀疑真实性

第四,卡夫卡的分区和并行性设计是其高吞吐量的横向扩展基础,一个卡夫卡主题(Topic)可以被划分为多个分区(Partition),每个分区都是一个独立的、有序的日志文件,这种设计带来了巨大的好处:不同的分区可以分布在不同的服务器(Broker)上,这意味着,生产者可以将消息并发地写入同一个主题的不同分区,从而充分利用整个集群的磁盘I/O能力,同样,消费者可以组成消费组,每个消费者实例可以独立地消费一个或多个分区,实现了消费能力的水平扩展,分区机制将负载分散到多台机器上,避免了单机瓶颈,使得卡夫卡能够通过增加机器来线性提升整体的吞吐量。

卡夫卡的端到端的低延迟设计也功不可没,它采用了“拉取”(Pull)模型,即由消费者主动向Broker拉取消息,而不是由Broker将消息推送给消费者,这种模式允许消费者根据自己的处理能力来调整消费速率,避免了Broker在消费者处理不过来时被拖慢,消费者在拉取消息时,如果没有新消息,可以选择进行“长轮询”,保持连接等待一段时间,而不是立即返回空结果,这既减少了不必要的网络往返,又保证了消息能被近乎实时地传递。

卡夫卡的“快”是一个系统工程的结果,它通过坚持顺序读写这个核心原则,辅以批处理与压缩、零拷贝技术、分区并行架构以及智能的拉取模型,将磁盘、网络和CPU的性能潜力压榨到了极致,这些设计选择环环相扣,共同造就了其令人难以置信的高吞吐量和低延迟,使其成为处理海量实时数据流的理想选择。