3. 主流消息总线对比:Kafka vs RabbitMQ vs RocketMQ vs Pulsar

做架构选型这么多年,我见过太多团队在消息中间件上「翻车」了。有的选了个吞吐量巨高的,结果业务逻辑复杂到没法实现;有的选了功能最全的,结果运维成本直接把人搞崩溃。说白了,没有最好的消息队列,只有最合适的。

今天我就把这四个主流选手——Kafka、RabbitMQ、RocketMQ、Pulsar,从架构到性能,从场景到坑,给你掰开了讲清楚。

3.1 四款消息总线的核心架构差异

先看一张我画的架构对比图,这样你脑子里能有个整体印象。

四款消息总线架构对比 Kafka 分区 + 日志模型 Producer → Broker → Consumer 顺序写磁盘 零拷贝技术 Pull 模式 吞吐量:极高 RabbitMQ Exchange + Queue 模型 Producer → Exchange → Queue Erlang 开发 AMQP 协议 Push 模式 吞吐量:中等 RocketMQ Topic + Queue 模型 Producer → NameServer → Broker Java 开发 事务消息 Pull + Long Polling 吞吐量:高 Pulsar 分层架构 Broker + BookKeeper 计算存储分离 Segment 存储 多租户原生支持 吞吐量:极高 核心对比维度 存储模型 Kafka: 分区日志,顺序写 RabbitMQ: 队列存储,内存+磁盘 RocketMQ: 文件存储,CommitLog Pulsar: 分层存储,BookKeeper 消息模型 Kafka: 发布订阅 RabbitMQ: 多种路由模式 RocketMQ: 发布订阅 Pulsar: 发布订阅+队列 运维复杂度 Kafka: 依赖ZooKeeper RabbitMQ: 简单,原生集群 RocketMQ: 依赖NameServer Pulsar: 组件较多,但弹性好 延迟特性 Kafka: 毫秒级(批量) RabbitMQ: 微秒级 RocketMQ: 毫秒级 Pulsar: 毫秒级

3.2 逐个拆解:架构与特性

3.2.1 Kafka——流式处理的王者

Kafka 的架构,说白了就是一个「日志系统」。它把消息全部追加到分区日志里,消费者自己决定从哪读。这种设计让它天生适合高吞吐场景。

我记得有一次帮一个电商团队做双十一压测,Kafka 集群单机扛到了 50 万条/秒的写入,CPU 才用了 60%。这得益于它的顺序写磁盘和零拷贝技术。你想想看,别的消息队列还在内存里折腾,Kafka 直接往磁盘上怼,反而更快。

核心特性:

  • 分区并行:一个 Topic 拆成多个 Partition,并行读写
  • 顺序写入:磁盘顺序写比随机写快 6000 倍
  • 零拷贝:数据从磁盘到网卡,不经过用户态
  • Pull 模式:消费者自己控制消费速率

注意:Kafka 的强项是吞吐量,但它的消息路由能力很弱。如果你需要复杂的消息路由(比如按内容分发),Kafka 会让你很痛苦。我曾经见过一个团队用 Kafka 做订单状态机,结果路由逻辑写了一千多行,维护成本极高。

3.2.2 RabbitMQ——灵活路由的标杆

RabbitMQ 是这四个里面最「老牌」的。它用 Erlang 写的,天生就适合做高并发网络应用。它的核心模型是 Exchange + Binding + Queue,说白了就是一个「邮局」:你把信交给邮局,邮局根据地址(路由规则)投递到不同的信箱(队列)。

我个人习惯在需要复杂路由的场景下首选 RabbitMQ。比如我之前做一个多租户的通知系统,同一个消息要根据用户类型、通知渠道、优先级分发到不同的队列,用 RabbitMQ 的 Topic Exchange 几行配置就搞定了。

经验之谈:RabbitMQ 的延迟极低,能达到微秒级。但它的吞吐量上限不高,单机大概在几万条/秒。如果你对延迟敏感但对吞吐量要求不高,RabbitMQ 是很好的选择。

3.2.3 RocketMQ——阿里系的中场发动机

RocketMQ 是阿里巴巴开源的,说白了就是「Java 版的 Kafka 加强版」。它保留了 Kafka 的高吞吐特性,又加了很多企业级功能,比如事务消息、定时消息、消息回溯。

我参与过一个金融交易系统,对消息的可靠性要求极高。RocketMQ 的事务消息帮了大忙——它保证了「本地事务」和「消息发送」的原子性。如果消息发送失败,整个事务就回滚,不会出现「钱扣了但消息没发出去」的情况。

// RocketMQ 事务消息示例
TransactionListener transactionListener = new TransactionListenerImpl();
TransactionMQProducer producer = new TransactionMQProducer("group");
producer.setTransactionListener(transactionListener);
producer.start();

// 发送半消息
Message msg = new Message("order-topic", "create", orderJson.getBytes());
SendResult result = producer.sendMessageInTransaction(msg, null);
// 如果本地事务执行成功,消息才会被消费者看到

RocketMQ 的独特优势:

  • 事务消息:保证分布式事务的最终一致性
  • 定时消息:支持精确到秒级的延迟投递
  • 消息轨迹:可以追踪一条消息的完整生命周期
  • 批量消息:支持批量发送,提升吞吐

3.2.4 Pulsar——云原生的新贵

Pulsar 是这四个里面最年轻的,但它的架构设计最「现代」。它把计算和存储分开了——Broker 只负责计算,BookKeeper 负责存储。这意味着你可以独立扩缩容计算节点和存储节点。

嗯,这里要注意一点。Pulsar 的 Segment 存储机制很有意思:消息被分成一个个 Segment,每个 Segment 有多个副本。如果某个 Broker 挂了,另一个 Broker 可以立刻接管它的 Segment,几乎无感切换。我在做金融级消息系统时,Pulsar 的这种架构让我很放心。

个人感受:Pulsar 的多租户支持是原生的,不像 Kafka 需要靠 Topic 命名来隔离。如果你做的是 SaaS 平台,要给不同客户提供独立的消息空间,Pulsar 会省很多事。

3.3 选型指南:到底该选哪个?

我整理了一个选型决策表,你可以直接拿来用。

场景 推荐 理由
日志收集、大数据管道 Kafka 吞吐量最高,数据持久化好,生态丰富
微服务异步解耦 RabbitMQ 路由灵活,延迟低,运维简单
金融交易、订单系统 RocketMQ 事务消息可靠,消息不丢失
云原生、多租户平台 Pulsar 计算存储分离,弹性好,多租户原生
IoT 设备数据采集 Kafka / Pulsar 高吞吐,支持海量连接
需要消息回溯重放 Kafka / Pulsar 消息持久化时间长,支持按 offset 回溯

3.4 避坑指南

做选型这么多年,我踩过不少坑。分享几个典型的:

我曾经犯过的错:

  • Kafka 分区数设太多:有一次我把一个 Topic 设了 100 个分区,结果文件句柄数直接爆了。Kafka 每个分区对应一个日志文件,分区太多会导致文件系统压力大。建议分区数不超过 Broker 数量的 10 倍。
  • RabbitMQ 内存阈值没调:默认情况下 RabbitMQ 在内存使用超过 40% 时会开始阻塞生产者。我有个项目上线后突然消息发不出去,查了半天才发现是内存阈值的问题。
  • RocketMQ 的刷盘策略:异步刷盘虽然快,但 Broker 宕机会丢消息。金融场景一定要用同步刷盘,虽然慢一点,但数据安全第一。
  • Pulsar 的 BookKeeper 配置:BookKeeper 的 Journal 和 Ledger 要分开磁盘,否则 IO 竞争会很严重。我第一次部署时没注意,结果性能惨不忍睹。

3.5 小结

选消息总线,说白了就是做 trade-off。你要想清楚自己的核心诉求是什么:

  • 要吞吐量?选 Kafka 或 Pulsar
  • 要灵活路由?选 RabbitMQ
  • 要事务可靠?选 RocketMQ
  • 要云原生弹性?选 Pulsar

没有完美的消息队列,只有最适合你业务场景的。我建议你先把业务场景梳理清楚,再对照上面的表格做选择。如果实在拿不准,可以先用 RabbitMQ 快速验证业务逻辑,后期再根据性能瓶颈做迁移。

一句话总结:Kafka 是「快」,RabbitMQ 是「活」,RocketMQ 是「稳」,Pulsar 是「弹」。选哪个,看你最缺什么。