Kafka与RocketMQ深度对比
前言
很多人问: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 → 只存储 offsetQueue 里只存简要信息(主要是 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 的做法:
// 消费者拿到所有消息,自己过滤for(ConsumerRecordrecord:records){UserEventevent=parse(record);if(event.getType().equals("ORDER")){// 处理订单事件}// 其他事件直接丢弃}问题:消费者要拉取所有消息,然后手动过滤,浪费带宽和 CPU。
RocketMQ 的做法:
// 生产者发送时打上 TagMessagemsg=newMessage("user-events","ORDER",data);// 消费者订阅时指定 Tag,只拉取需要的消息consumer.subscribe("user-events","ORDER");Broker 端直接过滤,消费者只收到自己关心的消息。
5.2 事务消息
两者都支持事务,但含义不同。
Kafka 的事务:
保证生产者发送的多条消息,要么全部成功,要么全部失败。
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:原生支持延迟消息
Messagemsg=newMessage("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
看一下两个函数的返回值:
// mmap - 返回数据内容的指针void*mmap(void*addr,size_tlength,...);// sendfile - 返回发送了多少字节ssize_tsendfile(intout_fd,intin_fd,off_t*offset,size_tcount);- 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连支持一下,创造不易您们的支持是我的动力🌟