学完这篇,你能拿到一套可落地的判断标准:面对具体业务时,知道该在 RabbitMQ、Kafka、RocketMQ 之间选哪个,以及 Java 端接入时最容易踩的坑在哪。
第一步:先分清三者的出身和定位
选型前必须明确:这三个不是同类竞品的简单替代关系,设计目标本身就不同。
- RabbitMQ:Erlang 编写,实现 AMQP 协议。核心优势是路由灵活(直连、主题、扇出、头交换机)、延迟低(毫秒级)、单机吞吐几万级。适合业务解耦、任务分发。
- Kafka:Scala/Java 编写,本质是分布式提交日志,不是传统队列。吞吐十万级起步,靠分区 + 顺序写磁盘实现。适合日志采集、埋点、流式计算。
- RocketMQ:Java 编写,阿里开源后捐给 Apache。定位是金融级业务消息,吞吐十万级,同时具备事务消息、延时消息、消息回溯这些业务刚需特性。
一句话记:RabbitMQ 拼路由,Kafka 拼吞吐,RocketMQ 拼业务特性。
第二步:用五个维度量化对比
| 维度 | RabbitMQ | Kafka | RocketMQ |
|---|
| 单机吞吐 | 万级 | 十万级以上 | 十万级 |
| 延迟 | 微秒~毫秒 | 毫秒 | 毫秒 |
| 顺序消息 | 单队列内可保证 | 分区内保证 | 队列内保证,支持严格顺序 |
| 事务消息 | 不支持(需本地消息表兜底) | 支持(仅生产幂等语义) | 原生支持,含事务回查 |
| 延时消息 | 需插件 | 不支持(需自建) | 原生 18 个延时级别 |
| 消息回溯 | 不支持 | 支持(改 offset) | 支持(按时间戳回溯) |
| 运维成本 | 低 | 中(依赖 ZK/KRaft) | 中(NameServer + Broker) |
注意:表格里的吞吐是「单机量级参考」,实际值受消息体大小、副本数、磁盘类型影响极大。别拿网上的 benchmark 数字直接当结论,务必用自己的真实报文压测一遍。
第三步:按场景做决策
选 RabbitMQ 的情况:中小规模业务系统,需要复杂的路由规则(比如一个订单事件要按类型分发到库存、积分、通知三个不同队列),团队没有专职中间件运维。
选 Kafka 的情况:数据管道类场景——日志、埋点、CDC 变更捕获;或者下游要接 Flink/Spark Streaming 做实时计算;消息量大且允许「至少一次」语义。
选 RocketMQ 的情况:电商/金融交易链路。典型信号是这三个需求里中了一个:① 下单要发消息但必须和本地事务保持一致(事务消息);② 订单 30 分钟未支付自动关闭(延时消息);③ 同一订单的创建、支付、发货必须严格有序(顺序消息)。
注意:如果业务同时要事务消息和延时消息,基本可以排除 RabbitMQ 和 Kafka,直接上 RocketMQ,否则你得自己写本地消息表 + 定时扫表,维护成本远超收益。
第四步:Java 端接入的最小配置
Spring Boot 依赖三选一:
<!-- RabbitMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- Kafka -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<!-- RocketMQ -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
生产端必须开的可靠性参数:
spring:
rabbitmq:
publisher-confirm-type: correlated # 开启 confirm 回调
publisher-returns: true # 路由失败回调
listener:
simple:
acknowledge-mode: manual # 手动 ack,别用 auto
# Kafka
acks=all # 所有 ISR 副本确认
enable.idempotence=true # 幂等生产者,防重发
min.insync.replicas=2 # 至少 2 副本写入才算成功
注意:RocketMQ 的延时消息只支持固定的 18 个级别(1s/5s/10s/30s … 2h),不是任意秒数。要「30 分钟关单」得用级别 16,想自定义延时必须上 5.0 的定时消息。
第五步:三个高频踩坑点
坑一:消费幂等没做。 三者都只能保证「至少一次」,重复投递是常态。消息表加唯一业务键,或者用 Redis setnx 去重,别指望 MQ 帮你保证「恰好一次」。
坑二:消费端线程池打满。 Kafka 一个分区只能被一个消费者线程消费,分区数直接决定并行上限。分区数在创建 Topic 时就定好,后期扩容会导致消息重分布和顺序错乱。
坑三:消息积压后盲目扩容消费者。 先看是不是消费逻辑里有同步远程调用,多数积压是消费太慢而不是消费者太少。RabbitMQ 还要确认 prefetch 值是否合理,默认无限制会把消费者压垮。
小结
- 三者设计目标不同,不是替代关系:RabbitMQ 路由强、Kafka 吞吐强、RocketMQ 业务特性强。
- 决策顺序:先看是否需要事务消息/延时消息/严格顺序(选 RocketMQ),再看是否是数据管道场景(选 Kafka),剩下的选 RabbitMQ。
- Java 接入的核心动作是把可靠性参数打开:RabbitMQ 开 confirm + 手动 ack,Kafka 用
acks=all + 幂等生产者。
- 幂等必须自己做,任何 MQ 都只保证「至少一次」。
- 上线前用自己的真实报文压测,别信任何 benchmark 数字。