Kafka与RocketMQ深度对比
前言
很多人问:Kafka 和 RocketMQ 到底该选哪个?这篇文章我们就来深入对比一下这两个消息队列的架构差异、功能特性和性能表现,帮你做出更好的技术选型。
🏠个人主页:你的主页
文章目录
一、一句话总结两者差异
RocketMQ 是在架构上做减法,在功能上做加法。
什么意思呢?
- 架构做减法:简化了 Kafka 的一些设计,让系统更轻量
- 功能做加法:增加了很多 Kafka 没有的实用功能
但代价是什么?性能。Kafka 每秒能处理 17 万级别的数据,RocketMQ 是 10 万级别。不是 RocketMQ 弱,而是 Kafka 性能太强了。
二、架构上做减法
2.1 用 NameServer 替换 Zookeeper
Kafka 早期依赖 Zookeeper 来管理集群元数据。但 Zookeeper 是一个重量级的分布式协调服务,它能干的事情太多了:
- 服务注册与发现
- 分布式锁
- 配置管理
- Leader 选举
- ...
而 Kafka 只用到了其中一小部分功能,这就好比你只想切个苹果,却搬来一整套厨房设备。
RocketMQ 的做法是:既然用不到那么多功能,那就换一个更轻量的组件------NameServer。
打个比方:
- Zookeeper 像一个功能齐全的智能家居中控系统,能控制灯光、空调、窗帘、安防...
- NameServer 像一个简单的通讯录,只负责告诉你"某个服务在哪台机器上"
NameServer 的特点:
| 特性 | 说明 |
|---|---|
| 无状态 | 每个 NameServer 节点相互独立,不需要同步数据 |
| 轻量 | 代码量少,部署简单 |
| 高可用 | 挂掉一个不影响其他节点 |
不过值得一提的是,Kafka 从 2.8.0 版本开始也在逐步移除 Zookeeper 依赖,引入了 KRaft 模式。看来大家都意识到 Zookeeper 太重了。
2.2 简化分区模型
Kafka 把 Topic 拆分成多个 Partition (分区)来提升并发能力,RocketMQ 也一样,只不过换了个名字叫 Queue(队列)。
但两者的存储方式完全不同:
Kafka 的方式:
Topic
├── Partition-0 → 存储完整消息
├── Partition-1 → 存储完整消息
└── Partition-2 → 存储完整消息
每个 Partition 是一个独立的日志文件,消息直接写在里面。
RocketMQ 的方式:
Broker
├── CommitLog → 存储所有消息的完整数据(顺序写入)
├── Queue-0 → 只存储 offset(指向 CommitLog 的位置)
├── Queue-1 → 只存储 offset
└── Queue-2 → 只存储 offset
Queue 里只存简要信息(主要是 offset),真正的消息数据都在 CommitLog 里。
打个比方:
- Kafka 像是每个部门都有自己的档案柜,文件直接放在各自的柜子里
- RocketMQ 像是公司有一个统一的档案室(CommitLog),各部门只保留一个索引本(Queue),记录"我的文件在档案室的第几页"
三、存储模型的差异
3.1 读取性能对比
因为存储方式不同,读取消息的过程也不一样:
Kafka 读取消息:
1. 找到对应的 Partition
2. 直接读取消息 ✅ 一次搞定
RocketMQ 读取消息:
1. 从 Queue 读取 offset
2. 根据 offset 去 CommitLog 读取完整消息
RocketMQ 需要两次读取,看起来效率更低?别急,继续往下看。
3.2 写入性能对比
这里就是 RocketMQ 设计的精妙之处了。
Kafka 的写入问题:
假设一个 Broker 上有 100 个 Topic,每个 Topic 有 10 个 Partition,那就是 1000 个 Partition。每个 Partition 对应磁盘上不同位置的文件。
写消息到 Topic-A-Partition-0 → 磁盘位置 A
写消息到 Topic-B-Partition-3 → 磁盘位置 B
写消息到 Topic-C-Partition-7 → 磁盘位置 C
虽然单个 Partition 内是顺序写,但多个 Partition 分布在磁盘不同位置,整体上就变成了随机写。
打个比方:你要往 10 本不同的笔记本上写字,每写一行就要换一本,手忙脚乱。
RocketMQ 的解决方案:
所有消息不管属于哪个 Topic,统统写到同一个 CommitLog 文件里。
消息1(Topic-A)→ CommitLog
消息2(Topic-B)→ CommitLog
消息3(Topic-C)→ CommitLog
这样就把随机写变成了顺序写,磁盘 IO 效率大大提升。
打个比方:不管什么内容,都往同一本笔记本上写,写完一页翻下一页,行云流水。
结论:在多 Topic 场景下,RocketMQ 的写入性能优于 Kafka。
四、主从同步机制对比
数据可靠性需要主从备份,两者的同步方式也不同。
Kafka 的主从同步:
Broker-1 (Leader)
├── Partition-0 ──同步──→ Broker-2 (Follower) Partition-0
├── Partition-1 ──同步──→ Broker-3 (Follower) Partition-1
└── Partition-2 ──同步──→ Broker-2 (Follower) Partition-2
以 Partition 为单位同步,每个 Partition 单独建立同步通道。
RocketMQ 的主从同步:
如果还像 Kafka 一样按分区同步,就得把 CommitLog 里的内容拆开,又退化成随机读写了。
所以 RocketMQ 索性直接同步整个 CommitLog 文件:
Master Broker
└── CommitLog ──整体同步──→ Slave Broker CommitLog
以 Broker 为单位区分主从,大大简化了备份模型。
五、功能上做加法
RocketMQ 在功能上比 Kafka 丰富很多,这也是很多业务系统选择它的原因。
5.1 消息过滤(Tag)
假设你有一个 user-events 主题,里面有各种用户事件:注册、登录、下单、评论...
Kafka 的做法:
java
// 消费者拿到所有消息,自己过滤
for (ConsumerRecord record : records) {
UserEvent event = parse(record);
if (event.getType().equals("ORDER")) {
// 处理订单事件
}
// 其他事件直接丢弃
}
问题:消费者要拉取所有消息,然后手动过滤,浪费带宽和 CPU。
RocketMQ 的做法:
java
// 生产者发送时打上 Tag
Message msg = new Message("user-events", "ORDER", data);
// 消费者订阅时指定 Tag,只拉取需要的消息
consumer.subscribe("user-events", "ORDER");
Broker 端直接过滤,消费者只收到自己关心的消息。
5.2 事务消息
两者都支持事务,但含义不同。
Kafka 的事务:
保证生产者发送的多条消息,要么全部成功,要么全部失败。
java
producer.beginTransaction();
producer.send(msg1);
producer.send(msg2);
producer.send(msg3);
producer.commitTransaction(); // 三条消息原子性提交
这只是发送端的事务。
RocketMQ 的事务:
保证发消息 和本地业务操作要么同时成功,要么同时失败。
1. 发送半消息(Half Message)到 Broker,消费者暂时看不到
2. 执行本地事务(比如扣款)
3. 根据本地事务结果,提交或回滚消息
举个例子:
用户下单扣款场景:
- 发送"扣款成功"消息到 MQ
- 执行数据库扣款操作
如果消息发了,但数据库扣款失败了怎么办?RocketMQ 的事务消息可以保证两者一致性。
5.3 延迟队列
场景:用户下单后 30 分钟未支付,自动取消订单。
RocketMQ:原生支持延迟消息
java
Message msg = new Message("order-timeout", data);
msg.setDelayTimeLevel(5); // 延迟级别,比如 5 代表 1 分钟
producer.send(msg);
Kafka:不支持,需要自己实现(比如用定时任务扫描)。
5.4 死信队列
消费失败的消息去哪了?
RocketMQ:自动进入死信队列(Dead Letter Queue),方便后续排查和重试。
Kafka:原生不支持,需要自己实现(比如消费失败后手动发到另一个 Topic)。
5.5 消息回溯
想重新消费历史消息怎么办?
| 功能 | Kafka | RocketMQ |
|---|---|---|
| 按 Offset 回溯 | ✅ 支持 | ✅ 支持 |
| 按时间回溯 | ✅ 支持(0.10.1+) | ✅ 支持 |
这个功能两者都有,Kafka 从 0.10.1 版本后也支持按时间回溯了。
5.6 功能对比总结
| 功能 | Kafka | RocketMQ |
|---|---|---|
| 消息过滤(Tag) | ❌ 不支持 | ✅ 支持 |
| 事务消息 | ⚠️ 仅发送端事务 | ✅ 分布式事务 |
| 延迟队列 | ❌ 不支持 | ✅ 支持 |
| 死信队列 | ❌ 不支持 | ✅ 支持 |
| 消息回溯 | ✅ 支持 | ✅ 支持 |
六、性能差异的根本原因
前面说了,Kafka 性能(17万/秒)比 RocketMQ(10万/秒)高不少。RocketMQ 参考了 Kafka 的设计,为什么性能反而不如?
答案是:零拷贝技术的选择不同。
6.1 什么是零拷贝
消息队列的数据存在磁盘上。消费者要读取消息,数据需要从磁盘发送到网络。
传统方式(没有零拷贝):
磁盘 → 内核缓冲区 → 用户空间 → Socket缓冲区 → 网卡
(拷贝1) (拷贝2) (拷贝3) (拷贝4)
4 次拷贝,2 次系统调用,效率很低。
6.2 两种零拷贝方案
方案一:mmap(内存映射)
磁盘 → 内核缓冲区 ←映射→ 用户空间 → Socket缓冲区 → 网卡
(拷贝1) (不拷贝) (拷贝2) (拷贝3)
省掉了内核到用户空间的拷贝,还剩 3 次。
关键点:用户空间可以直接访问数据内容。
方案二:sendfile
磁盘 → 内核缓冲区 → 网卡
(DMA拷贝) (DMA拷贝)
只有 2 次拷贝,而且都是 DMA 控制器在干活,不占用 CPU。
关键点:用户空间完全不参与,也看不到数据内容。
6.3 为什么 RocketMQ 不用 sendfile
看一下两个函数的返回值:
c
// mmap - 返回数据内容的指针
void *mmap(void *addr, size_t length, ...);
// sendfile - 返回发送了多少字节
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
- mmap:应用层能拿到消息内容,可以做各种处理
- sendfile:应用层只知道发了多少字节,不知道具体内容是什么
RocketMQ 的很多功能需要读取消息内容:
- 消息过滤:需要读取 Tag
- 死信队列:需要知道是哪条消息失败了
- 事务消息:需要根据消息内容做二次投递
如果用 sendfile,根本拿不到消息内容,这些功能就没法实现了。
所以:
| 消息队列 | 零拷贝方案 | 原因 |
|---|---|---|
| Kafka | sendfile | 追求极致性能,不需要读取消息内容 |
| RocketMQ | mmap | 需要读取消息内容来实现丰富功能 |
这就是 RocketMQ 性能不如 Kafka 的根本原因。
七、如何选型
说了这么多,到底该选哪个?
7.1 选 Kafka 的场景
-
大数据场景:日志采集、实时计算、数据管道
-
关键词:Spark、Flink、Hadoop、数据湖、ETL
-
特点:数据量巨大,对吞吐量要求极高,功能需求简单
日志服务 → Kafka → Flink → 数据仓库
用户行为 → Kafka → Spark → 实时分析
7.2 选 RocketMQ 的场景
-
业务系统场景:电商、金融、订单、支付
-
关键词:事务、延迟、重试、可靠性
-
特点:功能需求复杂,对可靠性要求高,数据量相对可控
订单服务 → RocketMQ → 库存服务
支付服务 → RocketMQ(事务消息) → 积分服务
7.3 简单粗暴的选型标准
| 场景 | 推荐 |
|---|---|
| 能频繁听到 Spark、Flink 这些词 | Kafka |
| 其他业务场景 | RocketMQ |
八、总结
本文从架构、存储、功能、性能四个维度对比了 Kafka 和 RocketMQ:
| 维度 | Kafka | RocketMQ |
|---|---|---|
| 元数据管理 | Zookeeper(正在移除) | NameServer(轻量) |
| 存储模型 | 每个 Partition 存完整消息 | CommitLog 统一存储 |
| 多 Topic 写入 | 可能退化为随机写 | 顺序写,性能更好 |
| 主从同步 | 按 Partition 同步 | 按 Broker 同步整个 CommitLog |
| 功能丰富度 | 基础功能 | 消息过滤、事务、延迟、死信队列 |
| 零拷贝 | sendfile | mmap |
| 吞吐量 | ~17万/秒 | ~10万/秒 |
核心结论:
没有完美的架构,只有适合的场景。Kafka 追求极致性能,RocketMQ 追求功能丰富。做架构,做到最后,都是在做折中。
热门专栏推荐
- Agent小册
- Java基础合集
- Python基础合集
- Go基础合集
- 大数据合集
- 前端小册
- 数据库合集
- Redis 合集
- Spring 全家桶
- 微服务全家桶
- 数据结构与算法合集
- 设计模式小册
- 消息队列合集
等等等还有许多优秀的合集在主页等着大家的光顾,感谢大家的支持
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😊
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🙏
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🌟