Kafka 中文件的布局是以 Topic/partition 为主 ,每一个分区拥有一个物理文件夹,Kafka 在分区级别实现文件顺序写。如果一个 Kafka 集群中有成百上千个主题,每一个主题又有上百个分区,消息在高并发写入时,IO 操作就会显得很零散,效果相当于随机 IO。也就是说,Kafka 在消息写入时的 IO 性能,会随着 topic 、分区数量的增长先上升,后下降。

而 RocketMQ 在消息写入时追求极致的顺序写,所有的消息不分主题一律顺序写入 commitlog 文件, topic 和 分区数量的增加不会影响写入顺序。

根据我的实践经验,当磁盘是 SSD 时,采用同样的配置,Kafka 的吞吐量要超过 RocketMQ,我认为这里的主要原因是单文件顺序写入很难充分发挥磁盘 IO 的性能。

除了在磁盘顺序写方面的差别,Kafka 和 RocketMQ 的运维成本也不同。由于粒度的原因,Kafka 的 topic 扩容分区会涉及分区在各个 Broker 的移动,它的扩容操作比较重。而 RocketMQ 的数据存储主要基于 commitlog 文件,扩容时不会产生数据移动,只会对新的数据产生影响。因此,RocketMQ 的运维成本相对 Kafka 更低。

综合对比来看,在同等硬件配置一下,Kafka 的综合性能要比 RocketMQ 更为强劲。

RocketMQ 和 Kafka 都使用了顺序写机制,但相比 Kafka,RocketMQ 在消息写入时追求极致的顺序写,会在同一时刻将消息全部写入一个文件,这显然无法压榨磁盘的性能。而 Kafka 是分区级别顺序写,在分区数量不多的情况下,从所有分区的视角来看是随机写,但这能重复发挥 CPU 的多核优势。因此,在磁盘没有遇到瓶颈时,Kafka 的性能要优于 RocketMQ。

同时,Kafka 在服务端写入时使用了 FileChannel 的 transferTo 方法,底层使用 sendfile 系统调用,比普通的 FileChannel 的 write 方法更有优势。结合压测效果来看,如果待写入的消息体大小超过 64K,使用 sendfile 的块写入方式甚至比内存映射拥有更好的性能。

在消息发送方面,Kafka 的客户端则充分利用了批处理思想,比 RocketMQ 拥有更高的吞吐率。