Kafka 是一个高吞吐量、高性能的消息中间件,但是大厂经常问怎么实现的,很多同学回答不上来,下面我就全面来详解原因@mikechen
磁盘顺序写
首先,Kafka采用顺序写入,可以极大的提升性能。
什么是“顺序写入”?指的是将数据按照顺序写入磁盘,而不是随机写入。
顺序写入的操作方式,可以优化磁盘的 I/O 性能,因为磁盘连续写入的数据更快。
为什么更快呢?你需要深入了解磁盘IO的运行机制。
如下图所示:
如果你要写入数据,首先需要磁盘“寻道”,“寻道”就是磁盘磁头移动到目标轨道。
如果采用“随机写”,需要磁头在磁盘上来回移动,增加了寻道时间,降低了性能。
而采用顺序写入,通常不需要频繁移动磁头,磁头可以沿着相同的轨道顺序写入数据,减少了寻道时间。
所以,Kafka 在磁盘上,通过追加写入日志文件,这样每次写入操作都在文件末尾进行,而不是更新文件的任意位置。
如下图所示:
顺序写入将数据,写入到相邻的磁盘块中,保持数据的物理连续性,减少磁头移动。
顺序写入,使得数据在磁盘上的物理位置连续,从而减少了磁头移动、和等待时间,提高了写入性能。
零拷贝
Kafka 使用零拷贝技术,来优化数据从磁盘到网络的传输过程。
这减少了数据在内存、和磁盘之间的复制次数,从而减少了 CPU 使用率和延迟。
先来看看非零拷贝的情况,如下图所示:
采用非零拷贝,大致流程如下:
- 数据读取:首先,数据从磁盘读取,到内核缓冲区(内核空间);
- 数据复制:其次,数据从内核缓冲区,复制到用户空间的缓冲区。
- 网络传输:如果数据需要通过网络传输,数据再次从用户空间复制到网络缓冲区。
数据在传输、和处理过程中,会经历多次内存复制操作。
每次复制都会消耗 CPU 资源、和内存带宽,增加了系统开销。
所以,如果想体系性能,就可以考虑使用零拷贝技术,如下图所示:
比如:使用 sendfile
技术,可以将文件数据,从磁盘直接传输到网络套接字,而无需将数据复制到用户空间。
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
大致工作过程,如下:
首先,传输请求
应用程序发起 sendfile
调用,请求将文件描述符中的数据发送到网络套接字;
然后,内核处理
操作系统内核,接收到 sendfile
请求后,直接在内核空间中处理数据传输。
数据从文件描述符中读取到内核缓存中,再从内核缓存中写入到网络套接字,而无需将数据拷贝到用户空间。
最后,数据传输
数据在内核空间中完成读取和写入操作,从而避免了用户空间到内核空间的多次内存复制。
页缓存技术
Kafka 的高性能,与操作系统的页缓存(Page Cache)密切相关,理解这一点可以帮助更深入地认识 Kafka 。
我们一起来看Kafka的写入过程,如下图所示:
当 Kafka 生产者将数据写入主题时,这些数据首先被写入页缓存,而不是直接写入磁盘。
操作系统会将数据缓存到内存中,随后再将其异步地写入磁盘,比如:采用定期的策略等。
为什么要这样来实现呢?原因很简单:就是内存的访问速度,远快于磁盘。
通过这种机制,Kafka 利用内存的高速特性来优化数据写入,同时减少了对磁盘的直接 I/O 操作。
Kafka 通过批量操作将数据合并写入页缓存,减少了磁盘写入的次数,从而,进一步提升了系统吞吐量。
高效的网络设计
Kafka 使用了高效的网络协议,来减少网络开销。
比如:Kafka 的协议使用了高效的序列化和反序列化机制,减少了网络传输的数据量和处理延迟。
以及,Kafka 支持对消息进行压缩(如 :GZIP、Snappy、LZ4……. 等),通过压缩减少存储空间的占用、和网络传输的开销。
这减少了磁盘 I/O 和网络带宽的消耗,提高了总体性能。
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》