「為什麼選 Kafka?」「為什麼從 RabbitMQ 改成 Kafka?」這類問題的答案藏在演進史裡。
每一代 message queue 不是「比較新」「比較潮」就被選——是前一代撞了什麼極限驅動下一代出現。理解這個 timeline,你選 broker 時的判斷會準很多。
這篇按時序串起 5 代主流 MQ:每代解的問題 + 撞的新牆。
2003 — ActiveMQ / JMS:第一代企業級 MQ
背景:Java 生態當時統治企業軟體。Sun 推 JMS(Java Message Service)規格,Apache ActiveMQ 是最知名實作。
解決的極限:
在 ActiveMQ 之前,跨系統通訊只有兩種選擇——RPC(同步、阻塞、互相耦合)或自己寫 socket(每家公司重造輪子)。ActiveMQ 把「訊息傳遞 + 持久化 + 失敗重試」變成 standard service,跨系統解耦變成可能。
新撞的牆:
- 配置複雜:JMS 規格本身龐大,光配置 connection factory / destination 就要寫一坨 XML
- 效能差:每個訊息走 Java 序列化、broker 內部多層抽象,throughput 上不去
- clustering 痛苦:master-slave 架構,failover 慢且容易資料不一致
- 跨語言不友善:JMS 是 Java-centric,PHP / Python / Node.js 接 ActiveMQ 痛苦
ActiveMQ 統治企業軟體大約 5 年。直到——
2007 — RabbitMQ:跨語言通用 broker
背景:Erlang 寫的(電信業背景,天生擅長 high concurrency / fault tolerance)。實作 AMQP 規格——一個跨語言、跨平台的開放標準。
解決 ActiveMQ 的極限:
- 跨語言友善:AMQP 是 wire protocol 級的標準,任何語言寫個 client library 就能接
- 配置直觀:Exchange / Queue / Binding 三層 mental model 比 JMS 好懂
- routing 強大:Topic Exchange、Direct Exchange、Fanout Exchange 涵蓋大部分 routing 需求
- 效能更好:Erlang VM 處理高並發比 JVM 強
RabbitMQ 在 2010 年代成為「general-purpose MQ」的事實標準——SaaS、enterprise、startup 都用。
新撞的牆:
- 大量數據場景 throughput 不夠——當公司資料規模到「每秒百萬訊息」級別(log aggregation、user activity、metrics),RabbitMQ 的 disk I/O + memory 會撞牆
- 重新消費歷史訊息困難——RabbitMQ 是「消費完即刪」設計,想要「Consumer 從 offset N 開始重新讀」幾乎不可能
- Consumer 數量擴展受限——傳統 queue 模型是「一個訊息給一個 consumer」,scaling 模型不適合 fan-out 場景
LinkedIn 2011 年遇到第三點撞牆——他們需要 fan-out 個人 activity 到 dozens of downstream consumer——RabbitMQ 不適合。於是他們做了——
2011 — Kafka:log-based 大數據 streaming
背景:LinkedIn 內部 2009 開始做、2011 年 open source。Scala 寫的(後來核心改成 Java + Scala 混合)。
解決 RabbitMQ 的極限:
- log-based 架構:訊息追加寫進 partition、永久(可配置)保留——consumer 可以從任意 offset 開始讀
- fan-out 天生擅長:多個 consumer group 各自獨立讀同一個 topic,互不影響
- Throughput 高一個級距:sequential disk write + zero-copy 讀,單機可達每秒百萬訊息
- 適合大數據生態:原生跟 Spark / Flink / Hadoop 整合好
Kafka 在 2015+ 成為「大數據 streaming」的標準——LinkedIn / Netflix / Uber / Airbnb 都用。
新撞的牆:
- 運維重:ZooKeeper 依賴(直到 KRaft 才解)、broker / partition / replica 配置複雜、JVM tuning 必修課
- 小規模 overkill:1000 訊息/秒以下的場景上 Kafka 是用大砲打蚊子
- 延遲高於 RabbitMQ:Kafka 為 throughput 優化,p99 latency 在輕量場景反而比 RabbitMQ 差
- Pull 模型 + Consumer Group 學習曲線陡:partition / consumer group / rebalance 等概念需要花時間消化
這推著兩個方向的演化:輕量化 跟 整合化——
2017 — Redis Streams:簡單到「就用 Redis」
背景:Redis 5.0 (2018 release) 引入 Streams 資料結構——log-based 設計借鑒 Kafka,但住在 Redis 裡。
解決 Kafka 的極限:
- 零運維:Redis 你已經有了(cache 用),不用多裝一套 broker
- 延遲低:in-memory + Redis 的單線程模型,p99 latency 是 Kafka 的 1/10
- 學習成本低:XADD / XREAD / XACK 幾個指令就上手
- 適合中小規模:每秒幾千到幾萬訊息的場景剛好
新撞的牆:
- persistence 取捨:Redis 是 in-memory,AOF / RDB 持久化跟 Kafka 的 disk-first 比可靠性弱一個級距
- 大規模 throughput 還是輸 Kafka:每秒百萬等級時 Redis Streams 撐不住
- Consumer Group 比 Kafka 簡化但功能也少
2018+ — NATS / NATS JetStream:cloud-native 時代的輕量選擇
背景:NATS 由 Synadia(前 Apcera 團隊)打造。JetStream 是 NATS 的 persistence 層,2020 年穩定。
解決前面所有人的極限:
- 超低延遲:p99 < 1ms 級別(Kafka 通常 10ms+)
- 單一 binary 部署:純 Go 寫的,下載 binary 啟動就能跑(vs Kafka + ZooKeeper / KRaft + JVM tuning)
- Cloud-native:原生 K8s / mesh 支援、subject-based routing 比 Kafka topic 更彈性
- JetStream 補上 persistence:保留了 NATS 輕量但加上 Kafka-like 的 log-based persistence
目前的牆:
- 生態小:相比 Kafka 的龐大生態(Kafka Connect / Schema Registry / KSQL),NATS 工具鏈少
- 客戶端成熟度:主流語言 client 都有但 ecosystem 還在累積
- 「沒人因為選 Kafka 被開除」——保守決策還是會選 Kafka
把演進畫成一張圖
ActiveMQ (2003) Kafka (2011) NATS / NATS JS (2018+)
JVM-heavy / JMS-only log-based / 高 throughput 超輕量 / cloud-native
↓ 跨語言、太重 ↓ 運維重、小規模 overkill
RabbitMQ (2007) Redis Streams (2017)
AMQP / 跨語言通用 零運維、in-memory
↓ 大量 fan-out 撞牆 ↓ persistence 弱於 Kafka
↓
Kafka 或 RabbitMQ ─→ 互相撞對方的牆 ─→ 演化出共存
重要結論:這不是「Kafka 取代 RabbitMQ」的線性故事——是兩個解不同問題的工具共存。RabbitMQ 在 2024+ 仍是 general-purpose MQ 的主流;Kafka 在 streaming / 大數據是主流;NATS / Redis Streams 在輕量場景補上空缺。
每一代解的極限對照
| 從 | 撞了什麼極限 | 下一代解了什麼 |
|---|---|---|
| ActiveMQ | JMS 重、跨語言不友善 | RabbitMQ 跨語言 + 直觀 |
| RabbitMQ | 大量 fan-out + 重消費歷史不行 | Kafka log-based + Consumer Group |
| Kafka | 運維重 + 小規模 overkill | Redis Streams 零運維、NATS 輕量 |
| Redis Streams | persistence 不如 Kafka | NATS JetStream 補上 |
| NATS | 生態小、保守選型仍偏 Kafka | (正在發生中) |
反思
技術演進的靈魂是極限,不是版本號。
每一代 message queue 出現都對應到「上一代解不了的問題類別」。如果你選 broker 時只看「哪個比較新比較潮」,會錯過真正該問的問題:
「我的場景到底撞了哪一代的牆?」
如果你的場景連 RabbitMQ 都還沒撞牆——上 Kafka 是給自己增加 5 倍運維成本,沒有 leverage。如果你的場景已經到 Kafka 都嫌重——NATS / Redis Streams 才是該看的。
下一篇會深入講「演進驅動力」這個 angle——具體 case 怎麼判斷「你的場景到了哪一代」。