Kafka 和 RocketMQ 作为当今最主流的分布式消息中间件,其惊人的吞吐量和极低的延迟,核心得益于对操作系统底层特性的极致利用以及巧妙的架构设计。
虽然它们的实现细节有所不同,但保障高效读写的底层逻辑高度相似。我们可以从通用核心设计、Kafka 的特有优化以及RocketMQ 的特有优化三个维度来剖析。


一、 核心共同绝招:把硬件性能榨干


无论是 Kafka 还是 RocketMQ,它们能实现百万级 TPS 的基石都在于以下四点:
1. 顺序 I/O(Sequential I/O)
机械硬盘甚至 SSD 的随机读写性能都很差(因为需要寻道或垃圾回收),但顺序读写的性能堪比内存。

  • 做法: 两者都采用 Append-Only(只追加) 的模式写入日志文件。一旦写入就不再修改,删除也是通过定时清理整个文件来实现,这就将磁盘的随机写完全变成了高效的顺序写。

2. 充分利用 Page Cache(页缓存)
如果每次读写都直接操作磁盘,速度肯定跟不上。

  • 做法: 它们大量依赖操作系统的 Page Cache。写入消息时,实际上只是写入到操作系统的页缓存中,然后由操作系统异步刷盘(Flush)。读取消息时,如果刚好能在 Page Cache 中命中,就直接从内存返回,完全不需要进行磁盘 I/O。

3. 零拷贝技术(Zero-Copy)
传统的数据传输需要经历:磁盘 -> 内核缓冲区 -> 用户缓冲区 -> Socket 缓冲区 -> 网卡,中间经历了 4 次复制和多次上下文切换。为了消除这种无谓的开销,它们引入了零拷贝:

  • Linux sendfile: 数据直接在内核中从 Page Cache 传输到 Socket 缓冲区(Kafka 核心使用)。
  • Linux mmap(内存映射): 将磁盘文件映射到进程的虚拟内存空间,读写文件就像读写内存一样高效(RocketMQ 核心使用)。

4. 批量操作与压缩(Batching & Compression)

  • 批量: 无论是网络传输、磁盘写入还是消费,它们都支持将多条消息打包成一个 Batch 进行处理,极大减少了网络连接的开销和系统调用的次数。
  • 压缩: 生产者可以对批量消息进行压缩(如 GZIP、Snappy、Zstd),在降低网络带宽的同时,也减少了磁盘存储空间的占用。

二、 Kafka 的高效密码:分区与文件分段


Kafka 的设计理念是极简与极致吞吐。
1. Partition(分区)并发模型
Kafka 的 Topic 被划分为多个 Partition,它们分布在不同的 Broker 上。

  • 高并发: 每一个 Partition 都是一个独立的物理日志文件。这意味着多个生产者和消费者可以并行读写不同的分区,水平扩展能力极强。

2. 完美的 sendfile 闭环
Kafka 的消费模型非常简单:消费者直接按偏移量(Offset)顺序拉取。由于 Kafka 的消息在磁盘上的存储格式与网络传输的格式完全一致,Kafka 可以直接调用 Java 的 FileChannel.transferTo()(底层就是 sendfile)。
效果: 消息从 Page Cache 直达网卡,整个过程不经过 JVM 用户空间,几乎不占用 CPU,且规避了垃圾回收(GC)的影响。


三、 RocketMQ 的高效密码:集中写入与特殊机制


与 Kafka 不同,RocketMQ 诞生于阿里电商业务,面对的是海量 Topic、复杂的队列和对低延迟的极致要求。如果像 Kafka 那样一个分区一个文件,在几万个 Topic 情况下,Kafka 的顺序写就会退化为磁盘随机写。
为了解决这个问题,RocketMQ 进行了独特的优化:
1. CommitLog 与 ConsumeQueue 分离架构

  • 统一写入(CommitLog): RocketMQ 将所有 Topic 的消息全部顺序写入同一个文件——CommitLog。这保证了哪怕有几十万个队列,底层的磁盘写入永远是绝对的顺序 I/O。
  • 轻量索引(ConsumeQueue): 写入 CommitLog 的同时,后台异步线程会生成一个极其轻量化的索引文件 ConsumeQueue。消费者读取时,先查这个小索引,再通过索引里的 Offset 去 CommitLog 中拉取真正的数据。

2. mmap 的灵活运用
RocketMQ 默认使用 mmap(通过 Java 的 MappedByteBuffer)。相比 sendfilemmap 允许应用程序在用户空间直接修改和应用数据逻辑(例如 RocketMQ 需要在 Broker 端做消息过滤、延迟消息处理等)。
3. TransientStorePool(堆外内存缓冲池)
这是 RocketMQ 针对高并发写入引入的杀手锏。

  • 开启该特性后,消息写入时先写入到一整块**借来的、常驻的堆外内存(DirectByteBuffer)**中,然后由异步线程锁定并提交到 Page Cache,最后再刷盘。
  • 优势: 彻底将“写入”和“刷盘”在内存层面解耦,避免了高并发下 Page Cache 锁竞争导致的系统毛刺(Latency Spike)。

总结:两者的选择与权衡

优化维度KafkaRocketMQ
存储模型每个 Partition 对应一个独立日志文件所有 Topic 统一写入一个 CommitLog,配合 ConsumeQueue 索引
零拷贝技术核心使用 sendfile(高吞吐、不经用户态)核心使用 mmap(灵活性高,便于在 Broker 端做业务处理)
海量 Topic 支持较差(Topic 太多会导致顺序写退化为随机写)极佳(得益于统一的 CommitLog 架构)
适用场景大数据、日志采集、高吞吐指标监控电商业务、分布式事务、复杂消息过滤、低延迟金融场景
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐