← 回文章列表

2025年9月16日

Kafka 與 RabbitMQ 差在哪?從「佇列」和「日誌」兩種模型看怎麼選

KafkaRabbitMQMessage Queue事件驅動系統設計

前面分別寫過 RabbitMQ 的 Exchange、Queue、Binding、RabbitMQ 的 Ack 與死信佇列,以及 Kafka 完整入門、Kafka 實務注意事項。兩個我都在專案中用過,最常被問的問題就是:「那到底要用哪一個?」

答案要從它們最根本的差異開始講。

核心差異:佇列 vs 日誌

RabbitMQ 與 Kafka 核心模型比較:RabbitMQ 是佇列模型,Producer 發布到 Exchange,由 Broker 依 Binding 路由並推送給 Consumer,Consumer Ack 之後訊息就從 Queue 刪除,Broker 負責記住每則訊息的狀態,是聰明的 Broker、單純的 Consumer;Kafka 是日誌模型,Producer 附加到 Partition 尾端,Consumer 自己拉取並記錄 Offset,訊息讀完不刪除、依保留期限清除,不同的 Consumer Group 可以各自讀到不同的位置甚至倒回重讀,是單純的 Broker、聰明的 Consumer

RabbitMQ 是佇列(Queue):

  • Broker 負責路由:Producer 交給 Exchange,Exchange 依 Binding 決定複製到哪些 Queue
  • Broker 主動推送訊息給 Consumer,並追蹤每一則訊息的狀態(未投遞、處理中、已 Ack)
  • Consumer Ack 之後,訊息就從 Queue 刪除
  • 一句話:聰明的 Broker、單純的 Consumer

Kafka 是日誌(Log):

  • Producer 只是把訊息附加到 Partition 的尾端,Broker 不做路由
  • Consumer 自己拉取,自己記錄讀到哪個 Offset,Broker 不追蹤個別訊息
  • 訊息讀完不刪除,依保留期限或容量清除,任何人都可以從任何位置重讀
  • 一句話:單純的 Broker、聰明的 Consumer

幾乎所有其他的差異,都是從這裡推出來的。

逐項比較

RabbitMQKafka
模型佇列,處理完就刪除日誌,依保留期限清除
投遞方式Broker 推送(Push)Consumer 拉取(Pull)
處理進度Broker 追蹤每則訊息的 AckConsumer Group 記錄 Offset
路由Exchange + Binding,可依 Routing Key、萬用字元過濾只有 Topic,過濾要在 Consumer 端做
重讀歷史訊息不行,Ack 後就消失可以,把 Offset 倒回去
分工的平行度同一個 Queue 加 Consumer 就好,沒有上限受 Partition 數量限制
順序單一 Queue 單一 Consumer 時有序Partition 內有序,用 Key 控制
單則失敗處理Nack、Requeue、死信佇列,內建沒有單則 Ack,重試與死信要自己做
延遲訊息TTL + 死信,或 Delayed Message 外掛沒有內建
優先權支援 Priority Queue不支援
吞吐量每秒數萬筆等級每秒數十萬到百萬筆等級
訊息堆積堆積太多會影響效能,Queue 應該保持接近空堆積是常態,資料本來就存在磁碟上

同一個需求,兩邊怎麼做

分工:多個 Worker 一起處理

  • RabbitMQ:多個 Consumer 連到同一個 Queue(Competing Consumers)。工作量大就加 Consumer,沒有上限,搭配 Prefetch 讓慢的 Worker 少拿一點
  • Kafka:多個 Consumer 使用同一個 group.id。平行度上限是 Partition 數量,Consumer 比 Partition 多的部分只會閒置

所以像「產生報表」「轉檔」這種每件工作要跑好幾秒到好幾分鐘、數量又會暴增的任務,RabbitMQ 隨時加 Worker 的彈性比較好用。

廣播:每個服務都要收到

  • RabbitMQ:每個服務各自宣告一個 Queue,綁到同一個 Fanout 或 Topic Exchange
  • Kafka:每個服務使用不同的 group.id 訂閱同一個 Topic

兩者都能做,但 Kafka 的優勢是:新加入的服務可以從頭讀起,拿到上線之前的歷史事件;RabbitMQ 的新 Queue 只會收到綁定之後的訊息。

只收某些訊息:路由與過濾

  • RabbitMQ:Topic Exchange 的 Binding Key 用萬用字元過濾,例如 house.*.franchise 只收加盟物件,不需要的訊息根本不會送到 Consumer
  • Kafka:Consumer 會讀到整個 Topic,不需要的訊息要自己丟掉。如果某類訊息只有少數 Consumer 關心,通常會拆成獨立的 Topic

順序

  • RabbitMQ:單一 Queue 的訊息是先進先出,但只要有多個 Consumer 或發生 Requeue,順序就不保證。要嚴格有序,只能一個 Queue 一個 Consumer,等於放棄平行處理
  • Kafka:用 Key 讓同一個實體的訊息進同一個 Partition,同一個實體有序、不同實體平行,這是 Kafka 的強項

處理失敗的訊息

  • RabbitMQ:每則訊息獨立 Ack,失敗的那一則可以 Nack 送進延遲重試或死信佇列,其他訊息照常處理。這些機制都是內建的
  • Kafka:Consumer 提交的是「讀到哪個位置」,沒有「單獨標記某一則失敗」的概念。失敗的訊息要嘛原地重試、卡住整個 Partition,要嘛自己發到重試 Topic、死信 Topic,全部要自己設計

延遲處理

「訂單 30 分鐘沒付款就自動取消」這種需求:

  • RabbitMQ:TTL 加死信,或安裝 Delayed Message 外掛,訊息到時間才投遞
  • Kafka:沒有內建,通常要另外搭配排程或資料庫

事後重新處理

發現上週的資料處理錯了,修好程式要重跑一次:

  • RabbitMQ:訊息早就刪掉了,只能從資料庫或其他來源重新產生
  • Kafka:只要還在保留期限內,把 Consumer Group 的 Offset 倒回上週,重新消費一次就好

怎麼選

選 RabbitMQ 的情境:

  • 背景工作佇列:寄信、產生 PDF、轉檔,每件工作獨立、處理時間長短不一,需要隨時增加 Worker
  • 需要複雜路由:依事件類型、來源、地區把訊息分給不同的系統,讓 Broker 幫忙過濾
  • 每則訊息要個別處理成敗:失敗的要重試、重試不了的進死信佇列,不能卡住其他訊息
  • 需要延遲、優先權、RPC(Request/Reply)這類訊息層級的功能
  • 訊息量是每秒數千到數萬筆,處理完就不需要再看

選 Kafka 的情境:

  • 大量的事件串流:日誌、監控指標、點擊紀錄、IoT 感測資料,每秒數十萬筆
  • 同一份資料要給很多系統用,而且新系統要能補讀歷史資料
  • 需要重播:修正錯誤後重新處理、用事件重建讀取模型
  • 同一個實體的事件需要有序,又需要大量平行處理,例如帳務、交易事件
  • CDC(Change Data Capture):把資料庫的異動串流到其他系統

如果一句話:要「把工作交出去」用 RabbitMQ,要「把發生的事情記下來,讓大家各自去讀」用 Kafka。

使用情境:一個系統同時用兩個

兩者並不互斥。以一個電商的下單流程為例:

  • 訂單建立、付款、出貨等業務事件寫進 Kafka 的 order-events,以訂單 ID 為 Key:
    • 搜尋與報表服務各自用不同的 group.id 消費,建立自己的讀取模型
    • 資料分析平台從 Kafka 取得完整的歷史事件
    • 讀取模型的邏輯改了,就把 Offset 倒回去重建
  • 「寄送訂單確認信」「產生電子發票 PDF」這類背景工作丟進 RabbitMQ:
    • Worker 數量隨工作量隨時增減
    • 寄信失敗就延遲重試,信箱格式錯誤就進死信佇列,不影響其他人的信
    • 「30 分鐘未付款自動取消」用延遲訊息處理

判斷的方式是看這則訊息的本質:它是「一件已經發生、很多人可能有興趣的事實」,還是「一件需要有人去完成的工作」。

注意事項

  • 不要把 Kafka 當工作佇列用:處理時間長的工作容易超過 max.poll.interval.ms 觸發 Rebalance;一則失敗會卡住整個 Partition;Worker 數量又受 Partition 限制。這些都是 RabbitMQ 擅長的
  • 不要把 RabbitMQ 當事件儲存用:Queue 裡堆積大量訊息會吃記憶體與磁碟、拖慢效能,它的設計是讓 Queue 盡量保持接近空的狀態。需要長期保存、重播的,交給 Kafka 或資料庫
  • 兩邊的「至少一次」都一樣:不管是 RabbitMQ 的手動 Ack 還是 Kafka 的先處理再提交 Offset,訊息都可能被處理不只一次,Consumer 一定要冪等
  • 維運成本不同:RabbitMQ 單機就能跑起來,管理介面直覺;Kafka 需要規劃 Partition、複本、保留期限、磁碟容量,叢集維運的門檻比較高。訊息量不大、團隊又沒有 Kafka 經驗時,不要只因為「Kafka 比較快」就選它
  • 兩者都在互相靠近:RabbitMQ 3.9 加入了 Streams,提供類似 Kafka 的可重讀日誌;Kafka 4.0 也以 Early Access 推出了 Share Group(KIP-932),讓多個 Consumer 可以不受 Partition 限制地分工、逐筆確認。不過這些都還是各自的「延伸功能」,選型時還是以核心模型為主

一句話總結

RabbitMQ 是聰明的 Broker 加處理完就刪除的佇列,擅長路由、逐筆確認、延遲與重試,適合把工作交出去;Kafka 是單純的 Broker 加可以重讀的日誌,擅長大吞吐量、多系統各自消費、依 Key 有序與重播,適合把發生的事記下來讓大家各自讀;分清楚訊息是「工作」還是「事實」,就知道該放在哪裡。