「為什麼選 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 在輕量場景補上空缺。


每一代解的極限對照

撞了什麼極限下一代解了什麼
ActiveMQJMS 重、跨語言不友善RabbitMQ 跨語言 + 直觀
RabbitMQ大量 fan-out + 重消費歷史不行Kafka log-based + Consumer Group
Kafka運維重 + 小規模 overkillRedis Streams 零運維、NATS 輕量
Redis Streamspersistence 不如 KafkaNATS JetStream 補上
NATS生態小、保守選型仍偏 Kafka(正在發生中)

反思

技術演進的靈魂是極限,不是版本號

每一代 message queue 出現都對應到「上一代解不了的問題類別」。如果你選 broker 時只看「哪個比較新比較潮」,會錯過真正該問的問題:

「我的場景到底撞了哪一代的牆?」

如果你的場景連 RabbitMQ 都還沒撞牆——上 Kafka 是給自己增加 5 倍運維成本,沒有 leverage。如果你的場景已經到 Kafka 都嫌重——NATS / Redis Streams 才是該看的。

下一篇會深入講「演進驅動力」這個 angle——具體 case 怎麼判斷「你的場景到了哪一代」。