Kafka 作为消息队列中的中坚力量,基本上是每次面试必问的知识点。而说到 Kafka,大家对它的印象就是快!异常地快!
因此,为什么 Kafka 这么快,也是每次面试必问的知识点。对于混迹 Java 技术圈多年的我来说,Kafka 这么快的特性已经了然于胸。今天,就让我带着大家盘一盘!
Kafka 写入速度非常快,主要得益于其系统架构设计,包括:
- PageCache
- 批量压缩传输
- 顺序、批量写磁盘
- 多 partition 分散存储
PageCache
学过操作系统的同学都知道,内存是易丢失的存储介质,而磁盘则是不容易丢失的存储介质。但内存读写速度快,而磁盘读写速度慢。操作系统为了能提高写磁盘的速度,于是在内存中开辟了一小块,用来作为写入磁盘的缓冲,提高写磁盘的速度,这小块内存叫 PageCache。
Kafka 之所以这么快,其中一个很重要的点就是用了 PageCache。 Kafka broker 写入消息的时候,其实并不是直接写入文件,而是写入系统的 PageCache 内存,后续才有操作系统刷入文件中。通过这种方式,Kafka broker 就不直接写文件,而是直接写内存,这样就非常快速了!
因为有 PageCache 的存在,也有了所谓的刷盘。简单来说,就是同步刷盘,还是异步刷盘。同步刷盘,可以理解成写 PageCache 之后直接写磁盘。
这样的好处是消息不会丢失,但是坏处就是速度慢。异步刷盘则相反,写 PageCache 之后就结束,等待操作系统异步刷盘。这里说的「盘」指的就是「磁盘」。
Kafka 因此也提供了两个参数来控制刷盘方式,分别是:log.flush.interval.messages
和 log.flush.interval.ms
。前者表示数据达到多少条就将消息刷到磁盘,如果你希望数据不丢失,那么必须设置为 1。后者表示多久将累积的消息刷到磁盘。这两个参数任何一个达到指定值就触发写入。
批量压缩传输
我们都知道 Kafka 消息都是由生产者发送给 Kafka 服务器,再由 Kafka 服务器存储起来的。在很多情况下,系统的瓶颈不是 CPU 或磁盘,而是网络带宽,对于需要在广域网上的数据中心之间发送消息的数据流水线尤其如此。
Kafka 之所以能这么快,其中有一个很重要的原因是采用了批量压缩传输。在 Kafka 提供的客户端里,其每次发送给 Kafka 服务器的时候,并不是一条消息一条消息发送,而是一批消息一批消息发送,并且还会启用数据压缩算法。通过这种方式,原本可能 1 秒只能发送 1 条的能力,瞬间提升到了 1 千条,甚至一万条。
顺序、批量写磁盘
当消息到了 Kafka 服务器之后,Kafka 写入内存,最终还是需要写入磁盘。我们知道现在的磁盘大多数都还是机械结构(SSD 不在讨论的范围内)。
如果将消息以随机写的方式存入磁盘,就会按柱面、磁头、扇区的方式进行(寻址过程),缓慢的机械运动(相对内存)会消耗大量时间,导致磁盘的写入速度只能达到内存写入速度的几百万分之一。
为了规避随机写带来的时间消耗,Kafka 采取顺序写的方式存储数据,这样就减少了寻址的时间,极大地提高了写入速度。因此顺序写入磁盘,是 Kafka 之所以这么快的一个关键原因。 其次,Kafka 也采用消息批量写入磁盘的方式,每次写入一批数据,而不是只写入一条消息,这样就极大地提高了效率。
多 partition 分散存储
我们知道磁盘的写入是有物理极限的,如果同时有特别多的线程写入,达到了物理极限,那么其他线程就只能等待了。而 Kafka 存储的特点是小文件存储,并且切分成多个 Partition,分散在多个机器。这样读取的时候就可以充分利用磁盘的 IO,从而达到高效读取的目的。
试想,如果文件太大,并且只存在一个磁盘,那么该磁盘的压力得有多大?
总结
Kafka 的写入流程可以分为将数据传输到 Kafka 服务器,之后将数据写入磁盘。在数据传输阶段,Kafka 利用批量加压缩的方式,极大地提升了每次能发送的数据量,从而提高了写入速度。
而在写入磁盘环节,通过存储结构的设计,使得 Kafka 可以批量、顺序写入,从而减少磁盘寻道的时间。并且通过小文件的存储方式,提高了整体磁盘的耐受力。
批量写入、压缩的传输方式,与磁盘顺序写入、小文件多 partition 造就了 Kafka 强悍的写入速度!