题记与说明
- 主题:事件驱动系统与消息队列:Kafka、RabbitMQ、NATS、Redis Streams 的适用边界(主题研究)
- 精读日期:2026-10-31
- 方法:检索后精读 5 个来源(原文全文抓取)+ 2 个辅助来源(Confluent 对比页要点、NATS 官方文档保留策略要点),交叉比对架构模型、投递语义、基准数据与一线实践复盘
- 来源清单(5 个,均已全文精读):
- CloudAMQP(84codes,RabbitMQ/Kafka 托管商):*When to use RabbitMQ or Apache Kafka*(2025-02-14 更新)— https://www.cloudamqp.com/blog/when-to-use-rabbitmq-or-apache-kafka.html
- AutoMQ(Kafka 兼容云产品方):*Apache Kafka vs. NATS: Differences & Comparison*(2025-04)— https://www.automq.com/blog/apache-kafka-vs-nats-differences-amp-comparison
- AWS 官方对比页:*What's the Difference Between Kafka and Redis OSS?* — https://aws.amazon.com/compare/the-difference-between-kafka-and-redis/
- Onidel Cloud:*NATS JetStream vs RabbitMQ vs Apache Kafka on VPS*(2025-11-08,含 2025 基准)— https://onidel.com/blog/nats-jetstream-rabbitmq-kafka-2025-benchmarks
- dev.to(Mateusz Cholewka,一线工程复盘):*Beyond the Hype: Why We Chose Redis Streams Over Kafka for Microservices Communication*(2025-08-19)— https://dev.to/mtk3d/beyond-the-hype-why-we-chose-redis-streams-over-kafka-for-our-microservices-dmc
- (辅助精读)Confluent 官方对比页:*RabbitMQ vs Apache Kafka* — https://www.confluent.io/compare/rabbitmq-vs-apache-kafka/
- (辅助)NATS 官方文档 JetStream 章节页:*Retention policies / Stream and consumer policies* — https://docs.nats.io/learn/jetstream/retention-policies 、https://docs.nats.io/learn/jetstream/policies (经检索摘要获取要点,未逐字通读)
一、核心问题:这份工作在解决什么问题
四个系统都落在"发布/订阅 + 消息传递"这个大前提之下,但它们是四种不同的架构哲学,而不是同一工具的四个版本:
| 系统 | 本质模型 | 一句话定位 |
|---|---|---|
| Apache Kafka | 分布式提交日志(append-only immutable log + 分区 + offset) | 事件流平台:记录、重放、流式分析 |
| RabbitMQ | 智能代理/哑消费者的消息队列(AMQP:exchange → queue → binding) | 通用消息代理:复杂路由、任务分发、per-message 确认 |
| NATS(core / JetStream) | 轻量连接层(subject 树发布订阅;JetStream 加持久化流) | 服务间低延迟通信 + 边缘/IoT 消息织网 |
| Redis Streams | Redis 内的内存日志流(XADD/XREADGROUP/XACK,consumer group) | 复用已有 Redis 的轻量事件管道 |
本主题要回答的核心问题:当需求特征(吞吐、延迟、持久化、重放、路由复杂度、团队运维能力、已有技术栈)不同时,应该选哪一个——各自的适用边界在哪里,越界使用会发生什么。 正如 CloudAMQP 开篇所批评的,多数讨论把问题问错了方向:
"If you're asking yourself if Apache Kafka is better than RabbitMQ or if RabbitMQ is more reliable than Apache Kafka, I want to stop you right there. … the decision of whether to go with RabbitMQ or Apache Kafka is dependent on the requirements of your project, and a true comparison can only be made if you have used them both with the correct setup in a fitting scenario."
(如果你在问"Kafka 是不是比 RabbitMQ 好",我要先打断你……选型取决于你项目的需求;只有在合适场景、正确配置下两者都用过,比较才有意义。)
— CloudAMQP, *When to use RabbitMQ or Apache Kafka*
二、主要主张:各家的适用边界
2.1 总主张:没有最好的队列,只有匹配需求驱动的队列
五个来源殊途同归给出同一结论:选型要先写出"架构驱动"(architectural drivers),再对着需求打分,而不是看社区声量。dev.to 的作者在真实项目中就是这么做的,他列出的四个驱动是:持久化与重放需求、运维复杂度、性能、学习曲线——并加上一个最容易被忽略的第五项:它是否已经在你的技术栈里。
2.2 Kafka 的边界:为"记录与重放"而生
CloudAMQP 对两者的经典定位(原文引述,出自其长期置顶的 StackOverflow 回答):
"RabbitMQ is a solid, mature, general-purpose message broker that supports several protocols such as AMQP, MQTT, STOMP, and more. RabbitMQ can handle high throughput. A common use case for it is to handle background jobs or to act as a message broker between microservices. Kafka is a message bus optimized for high-ingress data streams and replay. Kafka can be seen as a durable message broker where applications can process and re-process streamed data on disk."
(Kafka 是为高入口数据流和重放优化的消息总线:一个持久化的 broker,应用可以在磁盘上反复处理流数据。)
适用边界内:事件溯源、点击流/行为追踪、日志聚合、大数据分析管道、需要重放修复 bug 的流处理、审计要求。边界外/代价:不支持消息优先级;路由模型极简("Kafka does not support routing"——路由要靠多 topic + consumer group 或 Kafka Streams 自己搭);运维概念密度高(topic/partition/offset/consumer group/KRaft),CloudAMQP 坦言"Kafka 出故障后的修复过程更耗时、更混乱"。
2.3 RabbitMQ 的边界:为"路由与任务"而生
RabbitMQ 的杀手锏是四种 exchange(direct/topic/fanout/headers)+ 优先级队列 + per-message ack/nack + 死信队列 + 多协议(AMQP 0.9.1 原生,MQTT/STOMP 插件):
"Chief among RabbitMQ's benefits is the ability to flexibly route messages. Direct or regular expression-based routing allows messages to reach specific queues without additional code."
(RabbitMQ 的首要优势是灵活路由:direct 或正则路由让消息无需额外代码就能到达特定队列。)
适用边界内:长耗时后台任务(生成 PDF、发邮件)、微服务间的命令/事件总线、需要优先级插队、需要逐条确认与重投递的场景。边界外/代价:传统队列(classic/quorum)消费即删除,没有重放语义——直到 v3.9 引入 RabbitMQ Streams(append-only log,可重读)。CloudAMQP 特别指出:传统队列"空时最快",积压数百万条会耗尽内存,扩容方向是加 consumer(竞争消费)而非加节点——"Kafka is built from the ground up with horizontal scaling in mind, while RabbitMQ is mostly designed for vertical scaling"。
2.4 NATS 的边界:为"低延迟通信与轻运维"而生
AutoMQ 的对比给出核心反差:Kafka 的运维栈(ZooKeeper/KRaft + Connect + Streams + MirrorMaker)在 NATS 里很多是"开箱即有":
"Even if you take the zookeepers out of the picture, NATS remains much 'lighter' to run than Kafka. There are a lot of things that NATS does 'out of the box' for which with Kafka you would have to deploy Kafka Streams, connectors, and mirror maker or Replicator nodes on top of your broker nodes."
(就算把 ZooKeeper 拿掉,NATS 运行起来仍然比 Kafka "轻"得多。NATS 开箱即有的很多能力,在 Kafka 里你要在 broker 之上额外部署 Streams、connector、MirrorMaker。)
NATS 是双层结构:core NATS 是无持久化的 at-most-once fire-and-forget;JetStream 补上持久化(内存或文件存储、RAFT 复制、按时间/序号/数量重放)。官方文档进一步把 JetStream 的保留策略分为三种,其设计问题是"谁决定一条消息已经处理完":limits(按上限保留,接近日志模型)、interest/workqueue(消费者 ack 后即删,接近队列模型)——即 JetStream 可按流配置成"日志"或"队列"两种形态(https://docs.nats.io/learn/jetstream/retention-policies 、https://docs.nats.io/learn/jetstream/policies ,经检索摘要确认)。适用边界内:微服务间低延迟 RPC/pub-sub(原生 request-response 模型)、IoT/边缘计算(单二进制 <15MB、Go 实现、资源占用小)、多租户(account 级隔离——"Kafka does not natively support multi-tenancy")。边界外/代价:生态与客户端库成熟度弱于 Kafka(AutoMQ 引社区反馈:"Kafka and the client libraries seems to be much more stable. We had and still have issues on NATS Jetstream with Consumers");consumer group 概念对新手更绕("The concept of consumer group in Kafka is much cleaner than the same in NATS")。
2.5 Redis Streams 的边界:为"已有 Redis + 中等规模"而生
dev.to 复盘的决策表格(原文引述):
| Driver | Kafka | Redis Streams |
|---|---|---|
| persistence & replayability | 持久化到廉价磁盘,可从头重放 | 持久化到昂贵的 RAM,长流可行但更贵 |
| operational complexity | High | Low,或栈里已有 Redis 时 Very Low |
| performance | 最高吞吐、中等延迟 | 高吞吐、低延迟 |
| learning curve | 陡峭 | 平缓,与 Redis 其他场景同一套 API |
结论原文:
"Choose Redis Streams if you: Already have Redis in your stack / Need low latency and moderate throughput / Want minimal operational complexity. Stick with Kafka if you: Need to process millions of messages per second (for sure) / Need long-term persistence and replay capabilities / Have a dedicated infrastructure team."
(选 Redis Streams:栈里已有 Redis、需要低延迟+中等吞吐、想要最小运维复杂度;坚持用 Kafka:确定要每秒百万级消息、需要长期持久化与重放、有专职 infra 团队。)
边界外的三颗钉子(作者上线一年踩出来的):
- 内存上限只能按条数管:Streams 只能
XADD ... MAXLEN ~ 1000按长度近似裁剪,没有"按内存占用上限"的选项,payload 大小不可控时(如 webhook)要靠压缩(他们 gzip 压缩比约 3)或"流里只传元数据、大块进 S3"的混合方案。 - 淘汰策略会整流删除:LRU/LFU/Random 淘汰把整个 stream 当成一个 key——"if you set this policy to LRU, LFU, or Random, and stream is like any other key, it can be removed entirely"(参见 redis/redis#4543)。
- 重放与持久化的代价:重放要求保留已处理消息(不能 XDEL),而这全在内存里;重启不丢还得开 RDB/AOF 持久化。
2.6 关键辨析:AWS 页面讲的是 Redis pub/sub,不是 Redis Streams
AWS 对比页的多数否定结论(不保留消息、at-most-once、无法检测重复)针对的是 Redis 的传统 pub/sub,不适用于 Redis Streams(后者有 consumer group、XACK、at-least-once)。精读时必须做这个区分,直接引用 AWS 页面会系统性低估 Redis Streams 的能力,这是本次主题里最容易踩的"来源陷阱"(AWS 页面原文:"Redis OSS doesn't store messages after they are delivered. If no subscribers are connected to the stream, Redis OSS discards the messages"——描述的是 pub/sub 语义)。
三、方法:来源们如何论证
- 供应商/托管商对比页(AWS、CloudAMQP、AutoMQ):架构模型解释 + 功能矩阵 + 按用例归档("长任务→RabbitMQ;数据分析→Kafka"),CloudAMQP 还叠加了多年托管服务的客户案例(DoorDash、Softonic、MapQuest、Parkster)。
- 基准测试文(Onidel):固定配置(4 vCPU / 8GB RAM / NVMe 的 VPS)上对比吞吐、延迟,再叠加投递语义与最小资源配置的决策矩阵。
- 一线工程复盘(dev.to):先列架构驱动打分 → 深入机制(XADD/XGROUP/XACK/XTRIM 命令级演示)→ 上线一年后的"真实世界问题"清单(Redis 挂了怎么办、内存失控、淘汰策略、持久化)——这是五篇里唯一回答"用起来之后哪里疼"的来源。
四、数据与证据
4.1 Onidel 2025 基准(4 vCPU / 8GB / NVMe VPS,声明为优化配置下的结果)
| 指标 | Kafka | NATS JetStream | RabbitMQ |
|---|---|---|---|
| 吞吐 | 500k–1M+ msg/s(batching) | 200k–400k msg/s(持久化) | 50k–100k msg/s(durability) |
| 延迟 | 10–50ms(batching+副本开销) | 亚毫秒(内存)/ 1–5ms(持久化) | 5–20ms(随队列深度/持久化变化) |
| 最小生产配置 | 8+ vCPU / 16GB RAM | 2+ vCPU / 4GB RAM | 4+ vCPU / 8GB RAM |
| HA 机制 | 分区多副本 + ISR + 自动选主 | RAFT(R3 副本流)+ 全网状集群自愈 | quorum queues(RAFT)/ classic 主从 |
"__Performance Note:__ These benchmarks assume optimized configurations. Real-world performance varies significantly based on message size, persistence requirements, and cluster topology."
(该基准假设优化过的配置;真实性能随消息大小、持久化要求和集群拓扑显著变化。)— Onidel
4.2 投递语义对照(AutoMQ + Onidel 交叉)
| 语义 | Kafka | NATS | RabbitMQ | Redis Streams |
|---|---|---|---|---|
| at-most-once | ✗ | ✓(core NATS) | 可配置 | 可配置 |
| at-least-once | ✓(默认) | ✓(JetStream) | ✓(publisher confirm + consumer ack) | ✓(XREADGROUP + XACK) |
| exactly-once | ✓(幂等 producer + 事务) | JetStream:声明支持(去重窗口;AutoMQ 表述为 ✓) | ✗ | ✗(需业务侧幂等) |
注意:两来源对 JetStream exactly-once 的表述有出入(Onidel 称"exactly once delivery through deduplication based on message IDs";AutoMQ 的表格在 exactly-once 行也标了 JetStream ✓,但正文口径接近"强 at-least-once + 去重窗口")。NATS 官方文档检索到的要点只确认了三种保留策略与 ack/redelivery 机制,未直接背书 exactly-once——实际工程中应按"去重窗口内的有效一次性"理解,并以 docs.nats.io 原文为准。
4.3 其他关键证据点
- Confluent 官方口径(https://www.confluent.io/compare/rabbitmq-vs-apache-kafka/ ,Kafka 供应商视角):"RabbitMQ messages are stored in memory, while Kafka messages are stored on disk",因此 Kafka 更耐久但延迟略高;吞吐表述为 RabbitMQ "Millions of messages per second" vs Kafka "Billions of messages per second";其建议的混合用法是"RabbitMQ 做低延迟快速操作 + Kafka 做持久流"。注意该页把 RabbitMQ 存储笼统概括为"内存"(严格说是 Erlang VM 内存+可选落盘),且为 Kafka 卖家立场。
- 历史与成熟度:RabbitMQ 2007 年 vs Kafka 2011 年;Kafka 生态核心组件(Connect/Schema Registry/REST Proxy/Streams)多数为 Confluent Community License——禁止作为 SaaS 提供;RabbitMQ 为 MPL 许可、可被其他 AMQP broker 平替(CloudAMQP 的许可论证)。
- 云成本视角(AutoMQ 引社区实践):"For an equivalent workload NATS uses many less disk IOPS compared to Kafka, which if you are running on public clouds can make a very noticeable difference in your costs."(等价负载下 NATS 的磁盘 IOPS 远低于 Kafka,公有云上成本差异肉眼可见。)
- 混合部署是常态(AutoMQ 引社区):"I have seen various companies using both Kafka and NATS with Kafka for more data and NATS for messaging."(很多公司 Kafka 管数据、NATS 管消息,两者并存。)
- 运维上手(CloudAMQP 引 DoorDash 的 Zhaobang Liu):"We didn't spend any time learning RabbitMQ and it worked for years. It definitely reduced tons of operational cost during DoorDash's hyper-growth."(我们没花时间学 RabbitMQ,它跑了几年没出事,在 DoorDash 狂飙期省了大量运维成本。)
- Redis Streams 实测细节(dev.to):JSON payload gzip 压缩比 ~3;
MAXLEN ~(近似裁剪)不阻塞写入;XACKDEL(ACK 后且所有组确认才删)是 Redis 8.2 新增;PHP 生态(Predis/phpredis)无 ioredis 式 offline queue,Redis 单点宕机时丢消息风险要自己兜。
五、结论:适用边界决策框架
5.1 一句话版
要记录、要重放、要吞吐 → Kafka;要路由、要任务、要逐条确认 → RabbitMQ;要低延迟服务间通信、要边缘轻部署 → NATS;已有 Redis、要轻量管道 → Redis Streams。
5.2 四系统边界矩阵
| 维度 | Kafka | RabbitMQ | NATS / JetStream | Redis Streams |
|---|---|---|---|---|
| 吞吐量级 | 最高(磁盘顺序写+batching) | 中 | 高 | 中高(受内存限) |
| 延迟 | 中(10–50ms 级) | 中低(5–20ms) | 最低(亚毫秒级) | 低(内存读写) |
| 持久化 | 磁盘为主,廉价、可分层 | 传统队列消费即删;Streams 补日志模型 | JetStream 内存/文件可选 | 内存(昂贵),靠 RDB/AOF 兜底 |
| 重放 | 原生(offset + compaction) | 仅 Streams 队列 | JetStream 按时间/序号/数量 | 有但费内存,且重放与清理互斥 |
| 路由 | 无(靠 topic 规划/Streams 自建) | 最强(4 种 exchange + 优先级) | subject 通配树 | 无 |
| 扩展模型 | 水平扩展(分区/节点) | 垂直扩展为主 + 加 consumer | 集群自动均衡、全 mesh | 受单实例/集群内存约束 |
| 运维复杂度 | 高(概念多、生态组件多) | 中(管理 UI 友好) | 低(单二进制 <15MB) | 极低(若 Redis 已在栈中) |
| 甜区场景 | 事件溯源、日志聚合、流分析管道 | 长任务、工作流编排、复杂投递规则 | 微服务通信、IoT/边缘、多租户 | MVP、中等规模微服务事件管道 |
5.3 三条跨来源一致的高级结论
- "消费即删"与"日志式保留"是根本不同的交付模型:前者(RabbitMQ 传统队列)天然适合任务分发;后者(Kafka/RabbitMQ Streams/JetStream)才支撑事件溯源、消费者故障后重算、调试回放。选型第一步是判断你要哪类模型。
- 边界在融合,甜区在资源模型:RabbitMQ Streams 和 NATS JetStream 都在向 Kafka 的日志模型靠拢,功能表上的差距在缩小;但持久化的物理介质(Kafka=廉价磁盘、Redis Streams=昂贵内存、JetStream=可配)决定各自的成本甜区,短期不会被抹平。
- 混合是常态不是妥协:Kafka 做数据骨干 + NATS/RabbitMQ 做服务间消息,是五篇来源中被多个独立来源证实的企业实践;AutoMQ 明确把它写成推荐选项("using both technologies can provide the best of both worlds")。
六、局限:作者承认的与本人推断的
作者承认的:
- Onidel 明确声明基准"assume optimized configurations",且未公开消息大小、ack 配置、副本级别等测试细节——数字只能当量级参考,不能直接横比。
- CloudAMQP 自我声明其观点基于托管业务经验,且其 Kafka 托管服务(CloudKarafka)已于 2025-01-27 下线,立场天然偏向 RabbitMQ。
- AutoMQ 是 Kafka 兼容云产品厂商,对比文有引流动机(文末即 AutoMQ Cloud 广告),文中大量"社区声音"为社区讨论摘录,非系统调研。
- dev.to 作者明确指出多数文章是理论的("Most articles are theoretical"),他自己的经验限于 PHP + MVP 团队场景,泛化有限。
本人推断的(来源未明确说、但阅读交叉可见):
- AWS 页面存在语义混淆:把 Redis pub/sub 的 at-most-once/不保留结论直接放在"Redis"名下,未区分 Streams;引用它做 Redis Streams 结论是危险的(见 2.6)。
- JetStream exactly-once 口径不一致(见 4.2 表注);官方文档要点只确认了保留策略与 ack 机制,未直接背书 exactly-once,此处保持存疑。
- 五个来源均未覆盖 Pulsar/Redpanda/Kestra 等替代品,也未涉及 Kafka KRaft 模式对运维成本的实际改善幅度;"Kafka 运维复杂"的论断部分建立在旧版 ZooKeeper 时代的印象上。
- Onidel 的吞吐/延迟区间与其余来源(如 AutoMQ 引用的"NATS ~11M msg/s"营销数字)不在同一量级口径,说明消息中间件基准高度依赖配置,所有数字都应在自己的负载上复测。
七、对我的启发
- 先写架构驱动再选型(dev.to 方法,直接可复用):把"持久化与重放需求 / 运维复杂度 / 性能 / 学习曲线 / 是否已在技术栈"五项写下来打分,而不是从"哪个最火"出发。这套驱动清单对任何中间件选型(数据库、缓存、任务队列)都成立。
- YAGNI 在中间件上最灵:"The YAGNI principle applies perfectly here. … Redis Streams are also inexpensive to implement, so if you decide to switch to Kafka in the future, you won't have wasted too much work."(dev.to)——从轻量方案起步、留好迁移口,比一步到位押注重型基础设施更稳。
- 判断交付模型是第一问:拿到任何"要不要上消息队列"的问题,先问"消费后消息还要不要在?"——不要在(任务)→ RabbitMQ 式队列;要在(事件/审计/重算)→ Kafka 式日志。这一个问题的答案就能砍掉一半候选。
- 内存型消息系统必须显式治理内存:Redis Streams 的三条纪律(MAXLEN 近似裁剪、禁用会整流删除的 LRU 淘汰、必要时"流内传元数据+大对象外置 S3")是"能跑"与"能上生产"的分水岭,可当作 checklist。
- 对个人自动化/本地管线的启示(衔接已有 n8n、SQLite 精读笔记):本机或小团队规模的事件驱动(抓取→清洗→通知)用 Redis Streams 或 NATS 完全够用;引入 Kafka 只在"多消费组独立消费同一事件流 + 需要重放历史"真实出现时才值得。
- 对供应商内容的批判性阅读:AWS 的 pub/sub/Streams 混淆、Onidel 与 AutoMQ 的口径出入提醒我——中间件的"能力结论"必须回溯到官方文档与自己的基准,第三方对比页适合做地图,不适合做裁决。
附:本次精读的来源与检索路径
- 检索:WebSearch 4 组(三系统选型对比 / Redis Streams vs Kafka / 学术基准论文 / NATS 官方文档定向检索)+ 定向站内检索(nats.io、cloudamqp.com/rabbitmq.com)
- 精读(全文抓取,web reader):
- https://www.cloudamqp.com/blog/when-to-use-rabbitmq-or-apache-kafka.html (2025-02-14)
- https://www.automq.com/blog/apache-kafka-vs-nats-differences-amp-comparison (2025-04-07)
- https://aws.amazon.com/compare/the-difference-between-kafka-and-redis/ (页面更新于 2026-09)
- https://onidel.com/blog/nats-jetstream-rabbitmq-kafka-2025-benchmarks (2025-11-08)
- https://dev.to/mtk3d/beyond-the-hype-why-we-chose-redis-streams-over-kafka-for-our-microservices-dmc (2025-08-19,原载 https://mateuszcholewka.com/post/why-we-chose-redis-streams-over-kafka/)
- 辅助抓取(要点级):https://www.confluent.io/compare/rabbitmq-vs-apache-kafka/ (WebFetch 提取要点);https://docs.nats.io/learn/jetstream/retention-policies 与 https://docs.nats.io/learn/jetstream/policies (检索摘要确认 JetStream 三种保留策略)
- 未抓取/存疑项:redis.io streams-tutorial(重定向到 streams/ 未取得正文);NATS 官方博客《NATS and Kafka Compared》仅从检索摘要获知存在,未读原文;JetStream exactly-once 表述请以 docs.nats.io 原文为准。