「我们要上消息队列,选 Kafka、RabbitMQ 还是 RocketMQ?」这是架构评审里的高频问题,也是最容易被「哪个性能高选哪个」带偏的问题。三者不是同一维度的竞品,它们的存储模型、投递语义、消费模型从底层就不一样,决定了各自擅长的场景。本文不堆参数表,而是从设计哲学拆开它们的根本差异,给出可落地的选型判断。

三种截然不同的设计哲学

一句话定位:

  • Kafka:分布式提交日志(distributed commit log)。本质是一个高吞吐、可重放的持久化日志流,为数据管道和流处理而生。
  • RabbitMQ:经典消息代理(message broker),实现 AMQP 协议。核心是灵活的路由(exchange + binding),为复杂的企业级消息分发和任务解耦而生。
  • RocketMQ:脱胎于电商交易场景的消息中间件,在 Kafka 式日志存储的基础上,强化了事务消息、定时/延时消息、消息回溯等业务特性。

理解这三句话,比记任何 benchmark 都重要。下面从三个决定性维度展开。

维度一:存储与消费模型——pull 日志 vs push 队列

这是最根本的分野。

Kafka / RocketMQ 是「日志 + pull」模型。 消息被持久化追加到分区/队列的日志文件里,消费进度由一个 offset(消费位点) 表示。消费者主动 pull 拉取,自己维护读到哪了。关键特性是:消息被消费后不会立即删除,而是按时间或大小策略保留(如保留 7 天)。这带来两个能力——消息可被多个消费者组独立重复消费(各自维护自己的 offset),以及可回溯(把 offset 调回去重新消费历史数据,排查问题或重算时极有用)。

RabbitMQ 是「队列 + push」模型。 消息进入队列,broker 主动 push 给消费者,消费者 ack 确认后消息就从队列里删除了。它更接近传统「任务队列」的直觉:消息是待办事项,做完就划掉。没有 offset 概念,自然也不支持「把已经消费的消息再读一遍」。

这个差异直接决定一类场景的归属:需要重放/多订阅者各自消费/数据可回溯 → 选日志模型(Kafka/RocketMQ);消息是一次性任务、用完即弃 → 队列模型(RabbitMQ)天然契合。

类比:Kafka/RocketMQ 像一份录像带,你可以倒回去重看、好几个人各看各的进度;RabbitMQ 像叫号机的小票,叫到你、办完、票就作废了。

维度二:路由能力——RabbitMQ 的杀手锏

RabbitMQ 的 AMQP 模型在「消息该发给谁」这件事上灵活度碾压另外两个。它的核心是 Exchange(交换机),生产者只把消息发给 exchange,由 exchange 按规则路由到队列:

1
2
3
4
direct  : 按 routing key 精确匹配,路由到指定队列
fanout : 广播,无视 routing key,发给所有绑定队列
topic : 按通配符匹配(order.*.paid 这类),灵活订阅
headers : 按消息头属性匹配

这套机制让 RabbitMQ 能优雅表达「VIP 用户的订单走专属队列」「支付成功事件同时通知库存、积分、风控三个系统」这类复杂分发逻辑,而且配置在 broker 端、无需改生产者代码。

Kafka 的路由就「朴素」得多:生产者直接指定 topic + 分区(或按 key hash),没有 exchange 这层灵活路由。Kafka 的哲学是「broker 尽量简单、把复杂度留给客户端和流处理层」,这恰恰是它能做到极高吞吐的原因之一——broker 干的活少。

所以路由逻辑复杂、需要灵活的发布订阅拓扑 → RabbitMQ 优势明显。

维度三:投递语义与业务特性

Kafka:天然 at-least-once,靠分区内顺序 + 幂等生产者 + 事务支持可做到 exactly-once(流处理场景)。顺序保证是分区级的。

RocketMQ 的差异化主要在「业务友好的高级特性」,这些是它在电商交易场景沉淀出来的:

  • 事务消息:解决「本地数据库操作」与「发消息」的原子性问题(分布式事务的经典痛点)。采用两阶段:先发半消息(half message)对消费者不可见 → 执行本地事务 → 根据结果 commit/rollback 半消息;若生产者中途宕机,broker 会回查本地事务状态再决定投递。
1
2
3
4
5
1. Producer 发送 half message(消费者看不到)
2. Broker 确认收到,返回成功
3. Producer 执行本地事务(如扣库存写库)
4. Producer 根据结果发 commit / rollback
5. 若 broker 长时间没收到第 4 步 → 主动回查事务状态
  • 定时/延时消息:原生支持「30 分钟后投递」,做订单超时关闭这类需求开箱即用。Kafka 原生不支持延时消息,得自己绕(如时间轮 + 多 topic)。
  • 顺序消息:支持分区(队列)级顺序,机制上和 Kafka 类似(同一业务 key 进同一队列)。

RabbitMQ:靠生产者 confirm + 消费者 manual ack 实现 at-least-once;通过插件(如 delayed message exchange)支持延时;顺序在单队列单消费者下成立,但一旦多消费者并发就难保证。

性能与可靠性的工程权衡

抛开具体数字(受版本、硬件、配置影响极大,不可一概而论),定性结论是相对稳定的:

  • 吞吐量:Kafka 和 RocketMQ 因为顺序写日志 + 零拷贝 + 批量,吞吐量级显著高于 RabbitMQ,是大数据/日志/流场景的首选量级。RabbitMQ 的强项不在极限吞吐。
  • 延迟:RabbitMQ 在中低负载、小消息下端到端延迟很低,适合对实时性敏感的请求-响应式异步任务。Kafka 靠批量攒吞吐,单条消息延迟通常略高。
  • 堆积能力:日志模型(Kafka/RocketMQ)消息落盘、消费与生产解耦,能扛海量堆积;RabbitMQ 队列大量堆积时性能会明显劣化(早期消息常驻内存的设计影响),更适合「消息快进快出」。

选型决策清单

把场景往下面对号入座,比纠结参数有用得多:

  • 海量数据管道、日志采集、流式处理、需要消息重放/多消费者组Kafka。这是它的主场,生态(Kafka Streams、Connect、与大数据栈集成)也最成熟。
  • 复杂路由、灵活的发布订阅、企业系统间解耦、对单条延迟敏感的中小吞吐任务队列RabbitMQ。AMQP 的路由能力和成熟稳定是它的护城河。
  • 电商/金融交易场景,需要事务消息、定时延时消息、消息回溯,且要 Java 生态友好RocketMQ。它把交易场景的高级特性做成了一等公民。

常见踩坑

  • 拿 RabbitMQ 当数据管道扛大堆积:队列严重堆积时性能跳水,且没有原生重放能力,排查和重算很被动。大流量数据流别硬上 RabbitMQ。
  • 以为 Kafka 开箱即用 exactly-once:默认是 at-least-once,重复消费是常态,下游消费逻辑必须幂等。不做幂等就上生产,迟早出重复扣款这类事故。
  • 滥用 Kafka 分区数 / RabbitMQ 队列数:两者各有元数据和资源开销,盲目堆数量会拖垮 broker 故障恢复和稳定性。
  • 用 RocketMQ 事务消息却忽略回查幂等:回查 + 重投意味着本地事务和消费两端都得幂等,否则半消息机制反而引入新的重复问题。
  • 指望任何一个 MQ 替你保证全局顺序:三者的「有序」都是分区/队列级的局部有序,全局严格有序在分布式 MQ 里基本是个伪需求,要么牺牲并行度,要么在业务层重排。

小结

三者不是「谁更强」,而是「为什么不同」:Kafka 是为吞吐与重放而生的分布式日志,RabbitMQ 是为灵活路由而生的 AMQP 代理,RocketMQ 是在日志模型上叠加交易业务特性的中间件。选型先问三件事——要不要重放、路由复不复杂、有没有事务/延时这类业务特性,答案自然浮现,远比对着 benchmark 数字纠结靠谱。