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)。

总结:两者的选择与权衡

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

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

更多推荐