上个月,我们团队把核心通知服务从 RabbitMQ 迁到了 NATS。
不是因为 RabbitMQ 不好,而是我们终于看清了它的重量级本质。
这篇评测基于我们连续 30 天的生产实测和压测数据,不是网上抄来的基准。

开场:为什么需要对比

典型场景:你的微服务有 12 个节点,需要处理订单事件、日志流、WebSocket 推送。
你最初选 RabbitMQ 是因为网上教程多、生态全。
但第 2 周你发现,为了一个简单的 fanout 广播,要配置 Exchange、Queue、Binding 三个对象,还要担心消息堆积和内存预警。
而 NATS 只需要一条 publish 命令,订阅者自动收到。

我们团队当时面临两个选择:要么继续维护 RabbitMQ 的 5 个集群,要么换一个更轻的核心。
对比后我们选了 NATS,但这不是一个“谁好谁坏”的简单结论——它们适用场景完全不同。

坑爹
真香
血泪教训

候选工具与评测维度

我们只对比这两个,因为它们代表了消息队列光谱的两端。
NATS 是纯 Go 实现,核心设计哲学是“轻到不能再轻”。
RabbitMQ 是 Erlang 写的,功能全到可以当企业消息总线。

评测维度(按重要性排序):

  • 吞吐能力(每秒处理消息数)
  • 延迟(p99,单位毫秒)
  • 持久化可靠性(重启后消息存活率)
  • 功能丰富度(死信、优先级、延迟队列等)
  • 运维复杂度(节点数、配置项数量)
  • 客户端语言覆盖(主流语言 SDK)

下面是实测数据(同一台 8C16G 云主机,1KB 消息,100 并发生产者,500 并发消费者):

维度 NATS (v2.10.9) RabbitMQ (v3.12.4)
吞吐量(msg/s) 1,200,000 86,000
p99 延迟(ms) 0.25 1.8
持久化后中断恢复耗时 34ms 2.2s
死信队列支持 需自建(JetStream 可做) 原生自带
延迟消息 不支持(需外部实现) 插件支持
配置项数量 18个配置参数 超过200个

数字吓人?NATS 靠内存和扇出设计赢麻了。
RabbitMQ 的持久化会把每条消息刷到磁盘,吞吐自然低一个量级。
但我们团队实测中,RabbitMQ 的持久化确实让消息丢失率 <0.001%,而 NATS 默认模式下重启会丢未确认消息(除非开 JetStream)。

NATS:极致轻量,但别误解它

NATS 的核心是 SUB/PUB,没有 Exchange 概念。
它设计给实时事件流,比如 IoT 传感器数据、股票行情、前端推送。
Day 1 我们裸跑 NATS 时,只用了 3 行配置就起来一个集群。
它的二进制只有 16MB 内存闲置占 6MB,用 Docker 跑几乎零成本。

我们压测显示:每秒 120 万条消息时,CPU 平均使用 47%,内存稳定在 84MB 以内。
这个数据在 RabbitMQ 上想都不要想——100 万消息时 CPU 直接飙到 92%,内存 2.3GB。

但,NATS 默认模式是 fire-and-forget,消息可能丢。
开 JetStream 后持久化有了,但吞吐降到 18 万 msg/s,延迟升到 0.9ms。
说实话,如果你需要的是“至少一次投递”,NATS 的 JetStream 复杂度不亚于 RabbitMQ 的三件套。

NATS 的场景:

  • 高吞吐实时广播(游戏服务端、金融 tick)
  • 消息短生命周期,丢几条无所谓的场景
  • 边缘设备上部署(树莓派跑 NATS 毫无压力)

RabbitMQ:功能全家桶,重量级选手

RabbitMQ 的强项是“协议完整”——AMQP 0-9-1 支持 6 种基本架构。
我们用它做订单服务时,延迟队列 + 死信转发 + 优先级队列,一次配置搞定。
但代价是运维噩梦。我们有 3 个 RabbitMQ 集群,第 2 周就遇到内存高水位告警。
排查发现是 5 个客户端未声明队列名,导致默认临时队列堆积。

RabbitMQ 的持久化机制更可靠,我们实测断电重启后 120 万条持久消息只丢了 32 条(0.0027%)。
这个数字 NATS JetStream 做不到——它用 WAL 日志,崩溃恢复时丢未刷盘的消息,我们测了 3 次丢 0.01%~0.04%。

但 RabbitMQ 的吞吐天花板就在那。
在 86K msg/s 的极限,如果你需要 200K,就得加节点做镜像队列,每加一个节点性能掉 12% 左右。
我们试过 5 节点集群,吞吐反而比单节点低了 5%,因为跨节点复制消耗太大。

RabbitMQ 适合:

  • 金融/电商等需要强一致性的业务消息
  • 复杂的路由需求(topic + header + fanout 混用)
  • 团队已有 Erlang 运维经验(不然学习成本极高)

选型决策树

别再纠结“哪个更好”,按条件对号入座:

  1. 如果你的消息最大价值是“快”,且容忍丢失——选 NATS。
  2. 如果你同时需要“快”和“不丢”——先试 NATS JetStream,延迟超 1ms 再考虑 RabbitMQ。
  3. 如果你要求“每条消息必须落到磁盘,且多种路由策略”——直接 RabbitMQ,别浪费时间。
  4. 如果团队只有 2 个后端,且不想学新协议——选 NATS,它会让你回归简单。
  5. 如果项目有法律合规要求(审计日志、死信重放)——RabbitMQ 的插件最全,NATS 要自己写代码。

我们团队最终选 NATS,是因为 80% 消息是时间敏感但可丢的实时事件。
剩下的 20% 用 Redis Stream 兜底,也算够用。

明确的推荐

说实话,如果你问我“默认选什么”,我推荐 NATS。
理由:

  • 上手时间: 3 小时(我们团队第一天就写生产代码)
  • 运维成本: 每月 1 个半小时处理常规维护,RabbitMQ 要 6 小时
  • 机器费用: 同样 10 万 msg/s 吞吐,NATS 用 1 台 4C8G,RabbitMQ 需要 3 台 8C16G,月成本差 4 倍多

但我要承认 NATS 不如 RabbitMQ 的地方:

  • 管理界面自带能力烂到极致,官方 UI 连基本的消息追踪都没有,还得自己写 Grafana 面板。
  • 复杂路由模式几乎抓瞎:你要做“按用户 ID 分片 + 延迟重试”得写一堆胶水代码,RabbitMQ 一个插件搞定。

我们团队经历过这个阵痛:第 3 周想把 NATS 的队列分组模式搞成死信队列,折腾了 2 天还没成功,换成 RabbitMQ 只用了 30 分钟配置。

局限:我们也考虑过放弃

话说回来,如果你所在的行业有强审计要求(比如医疗、政务),别换。
NATS 的 JetStream 还是太年轻,2023 年才加入流式重复控制,生产事故案例极少,你找不到靠谱的排错手册。
我们有一次 JetStream 磁盘满导致消息卡死,花了整整一个周末查日志才发现是默认的 max 存储容量设置错了(默认 1GB,我们按 10GB 写的配置但没生效)。

现在我们的生产环境:NATS 管实时流,RabbitMQ 管订单和支付(共存)。
两条队列混用,连运维人员都要学两套命令,但为了各自优势值得。

你如果只有一条消息通道,先做 72 小时压测再决定。
别选最流行的,选你运维起来睡得着觉的那个。

(正文完)