訊息代理與事件代理:何時使用它們

帶你聊技術發表於2023-11-08

來源:小技術君

選擇正確的工具來滿足非同步處理需求的技術指南

作為後端開發人員,有一天你需要回答這個問題:

我需要構建一個使用分散式佇列的非同步應用程式,我應該使用哪個代理? 作為工程師,我們的本能是列出我們瞭解或希望熟悉的工具(如果它是一種新的和已知的技術),然後開始使用它。不幸的是,在那個時刻,我們錯過了第一個最重要的問題,這個問題需要在所有其他問題之前得到答案:我們的現有和有時未來的用例/需求是什麼,什麼工具能最好地解決它們? 這是我們在設計一個重要功能時的起點,當時工程師的本能佔了上風。我們的第一個問題不是最重要的問題,從那時開始,我們選擇正確工具的過程變得不太有效。我們的團隊開了幾次會,討論了我們對分散式佇列的需求,不同技術的不同限制和特性(來自不同的範例)讓關注點遠離了我們最重要的需求,也遠離了決策和共識的實現。 在那個時候,我們決定回到基本問題,問:我們試圖解決的用例是什麼,沒有讓步的餘地在哪些領域?一如既往,讓我們從需求開始。

步驟1:明確您要解決的問題以及技術/工具體系結構如何與您的目標和考慮保持一致

在選擇訊息代理或事件代理時,有很多事情要考慮:高可用性、容錯性、多租戶、多雲區域支援、能夠支援高吞吐量和低延遲等等,列舉不勝列舉。

大多數情況下,當閱讀有關事件代理或訊息代理的主要特性時,我們都是以大多數公司或產品從未完全使用或需要的最複雜用例為例的。

作為工程師,生活中有一句常用的話語:

“上帝在細節中,但魔鬼隱藏在細節之間。”

在選擇事件代理與訊息代理兩個正規化之間,"魔鬼"隱藏在更多的低層技術考慮因素中,比如:

訊息的消耗或生成確認方法、去重、訊息的優先順序、消費者執行緒模型、訊息的消耗方法、訊息的分發/擴散支援、毒藥藥處理等等。

概念之間的不同:橙子與蘋果

步驟2:瞭解兩種正規化之間的差異

事件代理

儲存一系列事件。通常,事件會按到達事件代理的順序附加到日誌(佇列或主題)上。主題或佇列中的事件是不可變的,其順序不能更改。

當事件釋出到佇列或主題時,代理識別主題或佇列的訂閱者,並使事件可供多種型別的訂閱者使用。

生產者和消費者不需要彼此熟悉。

事件潛在地可以儲存數天或數週,因為它們一旦被成功消耗,就不會從佇列/主題中刪除。

訊息代理

用於服務或元件之間的通訊。它透過非同步方式在應用程式之間傳輸由生產者接收的訊息。

它通常支援佇列的概念,其中訊息通常儲存一段時間。佇列中訊息的目的是在消費者可用於處理訊息並在成功消耗後刪除訊息。

不能保證佇列中訊息處理的順序,並且可以更改。

訊息代理與事件代理

通常,在處理短命令或面向任務的處理時,我們會傾向於使用訊息代理

例如,假設你在一家電子商務公司工作,想要將新產品新增到公司的網站。這可能意味著多個服務需要知道並以非同步方式處理此請求。

訊息代理與事件代理:何時使用它們

上圖顯示了RabbitMQ扇出訊息分發的使用,其中每個服務都有自己的佇列連線到扇出交換機。

產品服務傳送包含新產品資訊的訊息到交換機,交換機將訊息傳送到所有連線的佇列。

在從佇列成功消耗訊息後,它將被刪除,因為涉及的服務不需要保留或重新處理訊息。

在處理當前或歷史事件時,通常涉及大量資料,需要以單個或批次方式處理這些資料,我們會傾向於使用事件代理

例如,假設你在一個娛樂評級網站工作,你想為使用者新增一個新功能,用來顯示電影的編劇和導演。這些資訊雖然歷史儲存,但不對負責提供這些資料的服務可用。

訊息代理與事件代理:何時使用它們

上圖顯示了使用Kafka作為事件代理,它能夠從資料倉儲中提取數億部電影,以為每個

服務儲存的電影資訊附加所需的資訊。

Kafka可以在相對短的時間內接受大量的資料,而消費者可以有一個獨立的消費者組來單獨處理電影主題流。

需要注意的重要方面

正如我之前提到的,選擇合適的正規化時有很多事情要考慮。

我想討論一些關鍵的差異,這些差異通常可能成就或破壞您對技術的決策。

在這一部分,我將比較迄今為止最流行的兩種技術:Kafka(事件代理)和RabbitMQ(訊息代理),它們分別代表了這兩個正規化,我對它們都有實際經驗。

我強烈鼓勵您在技術選擇過程中考慮以下幾點。

輪詢與推送

Kafka消費者的工作方式是透過輪詢一個主題中按順序分割槽劃分的訊息的塊,每個消費者負責從一個或多個分割槽中消費訊息,其中分割槽用作消費者的並行機制(隱式執行緒模型)。

這意味著通常負責管理主題的生產者會隱式知道可以訂閱主題的消費者例項的最大數量。

消費者負責處理訊息處理的成功和失敗情況。由於訊息是從分割槽中批次輪詢的,所以訊息處理順序在分割槽級別是有保證的。

RabbitMQ消費者從佇列中接收訊息的方式是透過代理將訊息推送給它們。

每條訊息都以一種獨立的方式進行處理,消費者可以採用顯式執行緒模型,而不需要生產者知道消費者例項的數量。

成功的訊息處理是消費者的責任,而處理失敗主要由訊息代理完成。

訊息分發由代理進行管理。

如延遲訊息和訊息優先順序等功能是開箱即用的,因為訊息處理順序在佇列中通常是不保證的。

錯誤處理

Kafka處理訊息處理錯誤的方式是將處理錯誤的責任委託給消費者。

如果某條訊息被處理了幾次但失敗(毒藥藥),消費者應用程式需要跟蹤處理嘗試的數量,然後生成一條訊息到一個單獨的DLQ(死信佇列)主題,以便以後檢查/重新執行。

就錯誤處理而言,消費者是承擔所有責任的一方。

這意味著如果您希望具有重試/DLQ功能,您需要提供重試機制,並在傳送訊息到DLQ主題時充當生產者,這在某些極端情況下可能導致訊息丟失。

RabbitMQ處理訊息處理錯誤的方式是跟蹤處理訊息失敗。一旦一條訊息被視為毒藥藥,它將被路由到一個DLQ交換機。

這允許重新排隊訊息或將其路由到專用DLQ以進行檢查。

透過這種方式,RabbitMQ提供了保證未成功處理的訊息不會丟失。

消費者確認和傳遞保證

Kafka處理消費者確認的方式是由消費者提交從主題分割槽中輪詢的訊息的偏移量。

開箱即用,Kafka客戶端會自動提交偏移量,無論訊息是否成功處理,這可能導致訊息丟失,如下圖所示。

訊息代理與事件代理:何時使用它們

透過消費者程式碼負責手動提交獲取的訊息的偏移量,包括處理訊息消費失敗的情況,可以更改此行為。

RabbitMQ處理消費者確認的方式是消費者以每條訊息的方式進行“確認”或“否認”,允許由訊息代理處理重試策略/DLQ,如果需要,可以由訊息代理進行管理。

開箱即用,RabbitMQ客戶端自動進行確認,無論訊息是否成功處理,可以透過消費者端的配置手動控制確認,允許訊息在失敗/超時時重新推送給消費者。

RabbitMQ和Kafka在大多數情況下都提供至少一次訊息/事件處理的保證,這意味著消費者應該是冪等的,以處理同一訊息/事件的多次處理。

我們的流程

步驟 3:根據您的用例選擇技術,而不是反過來

對我們來說,最重要的部分是編制我們解決方案的技術標準清單,併為我們作為團隊和產品不能缺少的要求分配“不可接受”。

回到基礎精神,我使用了一個普通的表格來編制和比較不同的標準,並提到了一些需要注意的地方。記住,“細節藏在細節之中”。

訊息代理與事件代理:何時使用它們

這真的幫助我們組織並集中精力關注對我們至關重要的內容以及我們無法缺少的內容。

例如,我們的“不可接受”要求之一是,如果在處理過程中發生錯誤,我們不能承受丟失訊息。

正如您可能從上面的部分中記得的,當使用需要DLQ的Kafka時,消費者也是DLQ的生產者。這意味著在消費者發生故障的某些情況下,訊息將不會被髮送到DLQ主題,可能導致訊息丟失。

在這一點上,正如您可能已經猜到的那樣,我們決定選擇訊息代理。

我們的功能包括面向命令/任務的處理用例,訊息代理滿足了我們的產品/資料容量要求,也滿足了我們團隊的需求。

最後的思考

訊息和事件流生態系統包括許多解決方案,每個解決方案都有許多不同的方面需要考慮和熟悉。

重要的是我們要睜大眼睛進入每個生態系統,並對這些不同的正規化有清晰的理解。它們將對我們工程師的日常生活(有時是夜間生活)產生重大影響。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024922/viewspace-2993455/,如需轉載,請註明出處,否則將追究法律責任。

相關文章