RabbitMQ vs Kafka,我到底該如何選?

2024.01.26

身為一個有著大量微服務系統處理經驗的軟體架構師,我經常遇到一個不斷重複的問題:「我應該使用RabbitMQ 還是Kafka?」出於某種原因,許多開發人員認為這些技術可以互換的。雖然在某些情況下確實如此,但RabbitMQ 還是Kafka 之間根本存在根本上的差異。

因此,不同的場景需要不同的解決方案,選擇錯誤的方案會嚴重影響我們的軟體開發設計以及後續維護軟體。

本文的目標首先是介紹基本的非同步訊息傳遞模式。然後繼續介紹RabbitMQ 和Kafka 及其內部結構。第2 部分重點介紹了這些平台之間的關鍵差異、它們的各種優點和缺點,以及如何在兩者之間進行選擇。

非同步訊息傳遞模式

非同步訊息傳遞是一種訊息傳遞方案,其中生產者的訊息產生與消費者的訊息處理分離。在訊息傳遞系統中,我們通常會分成兩種主要的訊息傳遞模式:佇列模式和發布/訂閱模式。

隊列模式

在隊列模式中,隊列暫時將生產者與消費者解耦。多個生產者可以向同一個佇列發送訊息。然後當消費者處理訊息時,訊息會被鎖定然後從佇列中刪除,並且不再可用。

隊列模式通常就是一個訊息只能被一個消費者處理。

訊息佇列訊息佇列

附帶說明一下,如果消費者無法處理某個訊息,訊息平台通常會將訊息返回到佇列,以供其他消費者使用。除了解耦之外,隊列還允許我們擴展生產者和消費者,並針對錯誤處理提供容錯能力。

發布/訂閱模式

在發布/訂閱模式中,單一訊息可以由多個訂閱者同時接收和處理。

發布/訂閱發布/訂閱

例如,此模式允許發布者通知所有訂閱者係統中發生了某些情況。在RabbitMQ 中,主題是一種特定類型的pub/sub 實作(確切地說是一種交換類型),但在本文中,我將主題稱為整個pub/sub 的表示。

一般來說,訂閱有兩種類型:

  • 臨時訂閱,其中訂閱僅在用戶啟動並運行時才有效。一旦消費者關閉,他們的訂閱和尚未處理的訊息就會遺失。
  • 持久訂閱,只要未明確刪除,訂閱就會維護。當消費者關閉時,訊息平台會維持訂閱,稍後可以恢復訊息處理。

RabbitMQ

RabbitMQ 是訊息代理程式的一種實作— 通常稱為服務總線。它本身支援上述兩種訊息傳遞模式。訊息代理程式的其他流行實作包括ActiveMQ、ZeroMQ、Azure 服務匯流排和Amazon Simple Queue Service (SQS)。所有這些實現都有很多共同點,本文中描述的許多概念適用於其中的大多數。

尾巴

RabbitMQ 支援開箱即用的經典訊息佇列。開發人員定義命名佇列,然後發布者可以將訊息傳送到該命名佇列。反過來,消費者使用相同的佇列來檢索訊息來處理它們。

訊息交流

RabbitMQ 透過使用訊息交換器來實現pub/sub。發布者將其訊息發佈到訊息交換機,不用知道這些訊息的訂閱者是誰。

每個訂閱交換器的消費者都會建立一個佇列,然後訊息交換器將產生的訊息排隊供消費者使用。它還可以根據各種路由規則過濾某些訂閱者的消息。

RabbitMQ 訊息交換RabbitMQ 訊息交換

值得注意的是,RabbitMQ 支援臨時訂閱和持久訂閱。消費者可以透過RabbitMQ 的API 決定他們想要使用的訂閱類型。

由於RabbitMQ 的架構,我們還可以創建一種混合方法,其中一些訂閱者形成消費者群組,這些消費者群組以特定隊列上競爭消費者的形式共同處理訊息。透過這種方式,我們實現了發布/訂閱模式,同時也允許一些訂閱者擴展以處理接收到的訊息。

發布/訂閱和隊列相結合發布/訂閱和隊列相結合

阿帕契·卡夫卡

Apache Kafka 是一個分散式串流處理平台。

與基於佇列和交換的RabbitMQ 不同,Kafka 的儲存層是使用分區交易日誌實現的。Kafka 還提供了Streams API 來即時處理串流,以及Connectors API 來輕鬆與各種資料來源整合。不過,這些都超出了本文的範圍。

雲端服務商為Kafka 的儲存層提供了替代解決方案。這些解決方案包括Azure 事件中心,在某種程度上也包括AWS Kinesis Data Streams。Kafka 的串流處理功能還有特定於雲端的開源替代方案,同樣,這些也超出了本文的範圍。

主題

Kafka 沒有實作佇列的概念。Kafka 將記錄集合儲存在稱為主題的類別中。

對於每個主題,Kafka 都會維護一個分割區的訊息日誌。每個分區都是一個有序的、不可變的記錄序列,其中不斷附加訊息。

Kafka 在訊息到達時將其附加到這些分區。預設情況下,它使用循環分區器在分區之間均勻地傳播訊息。

生產者可以修改此行為以建立邏輯訊息流。例如在多租戶應用程式中,我們可能希望根據每個訊息的租戶ID 建立邏輯訊息流。在物聯網場景中,我們可能希望將每個生產者的身分不斷映射到特定分區。確保來自相同邏輯流的所有訊息映射到同一分區,以確保它們按順序傳遞給消費者。

卡夫卡生產者卡夫卡生產者

消費者透過維護這些分區的偏移量(或索引)並按順序讀取它們來消費訊息。

單一消費者可以使用多個主題,並且消費者可以擴展,直至與可用分區數量一致。

因此,在建立主題時,應仔細考慮該主題的訊息傳遞的預期吞吐量。共同消費某個主題的一群消費者稱為消費者群。Kafka 的API 通常負責消費者群組中消費者之間分區處理的平衡以及消費者當前分區偏移量的儲存。

卡夫卡消費者卡夫卡消費者

使用Kafka 實現訊息傳遞

Kafka 的內部實作其實很好地反映了pub/sub 模式。

生產者可以向特定主題發送訊息,多個消費者群組可以消費同一則訊息。每個消費者組都可以單獨擴展以處理負載。由於消費者維護其分區偏移量,因此他們可以選擇持久訂閱(在重新啟動時維持其偏移量)或臨時訂閱(即丟棄偏移量並在每次啟動時從每個分區中的最新記錄重新啟動)。

Kafka 其實是不太適合隊列模式的訊息傳遞。當然我們可以創建一個只有一個消費者群組的主題來模擬經典的訊息隊列。但這有多個缺點,在本文第2 部分我們將詳細討論。

第2 篇文章地址:https://betterprogramming.pub/rabbitmq-vs-kafka-1779b5b70c41

值得注意的是,無論消費者是否消費了這些訊息,Kafka 都會將訊息保留在分區中直至預先配置的時間段內。這種保留意味著消費者可以自由地重讀的消息。此外,開發人員還可以使用Kafka 的儲存層來實作事件溯源和稽核日誌等機制。

結束語

雖然RabbitMQ 和Kafka 有時可以互換,但它們的實現卻截然不同。因此,我們不能將它們視為同一類別工具的成員。一個是訊息代理,另一個是分散式串流平台。

作為解決方案架構師,我們應該認識到這些差異,並積極考慮針對給定場景應使用哪些類型的解決方案