事件驅動架構樣式
事件驅動架構是由 產生事件數據流的事件產生者 、 接聽這些事件的事件 取用者,以及 將事件從產生者傳送至取用者的事件通道 所組成。
事件以近乎即時的方式交付,因此取用者可以在事件發生時立即回應。 生產者與取用者分離:生產者不知道哪些取用者正在接聽。 取用者也會彼此解耦,每個取用者都會看到所有事件。 此程式與 競爭取用者模式 不同,其中取用者只會從佇列提取訊息,而且訊息只會處理一次,假設沒有任何錯誤。 在某些系統中,例如 Azure 物聯網(IoT),事件必須擷取到大量。
事件驅動架構可以使用 發佈-訂閱模型 或事件數據流模型。
Pub/sub: 發佈-訂閱傳訊基礎結構會追蹤訂用帳戶。 發行事件時,它會將事件傳送給每個訂閱者。 收到事件之後就無法重新執行事件,而且新的訂閱者看不到事件。
事件串流: 事件會寫入記錄。 事件會在分割區內嚴格排序,而且是永久性的。 用戶端不會訂閱數據流。 相反地,用戶端可以從數據流的任何部分讀取。 用戶端負責在數據流中提升其位置。 這表示用戶端可以隨時加入,而且可以重新執行事件。
在取用者端,有一些常見的變化:
簡單事件處理: 事件會立即觸發取用者中的動作。 例如,您可以使用 Azure Functions 搭配 Azure 服務總線觸發程式,讓函式在訊息發佈至服務總線主題時執行。
基本事件相互關聯: 取用者會處理一些離散的商務事件、將其與某些標識符相互關聯,並保存先前事件的資訊,以供處理後續事件時使用。 NServiceBus 和 MassTransit 等連結庫支援此模式。
複雜事件處理: 取用者會使用 Azure 串流分析等技術來分析一系列事件,並識別事件數據中的模式。 例如,您可以匯總時間範圍內嵌裝置的讀數,並在移動平均超過特定閾值時產生通知。
事件串流處理: 使用數據串流平臺,例如 Azure IoT 中樞或 Apache Kafka,作為內嵌事件的管線,並將其饋送至串流處理器。 資料流處理器會採取行動來處理或轉換資料流。 應用程式的不同子系統可能會有多個數據流處理器。 這種方法非常適合 IoT 工作負載。
事件的來源可能位於系統外部,例如IoT解決方案中的實體裝置。 在此情況下,系統必須能夠擷取數據源所需的磁碟區和輸送量的數據。
建構事件承載的主要方法有兩種。 當您控制事件取用者時,您可以決定每個取用者的承載結構。 此策略可讓您視需要在單一工作負載內混合方法。
在承載中包含所有必要的屬性: 當您想要取用者擁有所有可用的資訊,而不需要查詢外部數據源時,請使用此方法。 不過,這可能會導致數據一致性問題,因為有多個 記錄系統,特別是在更新之後。 合約管理和版本控制也可能變得複雜。
在承載中只包含索引鍵: 在此方法中,取用者會擷取必要的屬性,例如主鍵,以獨立擷取數據源的剩餘數據。 此方法提供更佳的數據一致性,因為它具有單一記錄系統。 不過,因為取用者必須經常查詢數據源,所以其執行效能可能會比第一種方法差。 您對於結合、頻寬、合約管理或版本控制的擔憂較少,因為較小的事件和更簡單的合約可降低複雜性。
在上圖中,每種取用者類型都會顯示為單一方塊。 為了避免取用者成為系統中的單一失敗點,通常會有多個取用者的實例。 可能需要多個實例來處理事件的磁碟區和頻率。 單一取用者可以處理多個線程上的事件。 如果事件必須依序處理,或只需要一次語意,此設定可能會建立挑戰。 如需詳細資訊,請參閱 最小化協調。
許多事件驅動架構中有兩個主要拓撲:
訊息代理程式拓撲: 元件會將發生事件廣播為整個系統的事件。 其他元件要麼對事件採取行動,要麼忽略事件。 當該事件處理流程相對簡單時,此拓撲很有用。 沒有集中協調或協調流程,因此此拓撲可以是動態的。 此拓撲高度解耦,可協助提供可擴縮性、回應性和元件容錯能力。 沒有元件擁有或知道任何多步驟商務交易的狀態,且這些動作是非同步執行的。 接著,分散式交易有風險,因為沒有原生方式可以重新啟動或重新執行。 您必須仔細考慮錯誤處理和手動介入策略,因為此拓撲可能是數據源不一致。
中繼器拓撲: 此拓撲可解決訊息代理程式拓撲的一些缺點。 有一個事件調解器可管理及控制事件的流程。 事件中繼程序會維護狀態,並管理錯誤處理和重新啟動功能。 與訊息代理程式拓撲相反,在此拓撲中,元件會將出現項目廣播為命令,而且只會廣播到指定的通道。 這些通道通常是消息佇列。 取用者應該處理這些命令。 此拓撲可提供更多控制權、更好的分散式錯誤處理,以及可能更佳的數據一致性。 此拓撲確實導入了元件之間的結合增加,而事件調解器可能會成為瓶頸或可靠性問題。
使用此架構的時機
您應該在下列情況下使用此架構:
- 多個子系統必須處理相同的事件。
- 需要具有最短時間延遲的實時處理。
- 需要複雜的事件處理,例如一段時間的模式比對或匯總。
- 需要大量數據和高速度,例如IoT。
福利
此架構的優點如下:
- 生產者和取用者解耦。
- 沒有點對點整合。 很容易將新的取用者新增至系統。
- 取用者可以在事件發生時立即回應事件。
- 高度擴充、彈性和分散式。
- 子系統具有事件串流的獨立檢視。
挑戰
保證傳遞。
在某些系統中,特別是在 IoT 案例中,保證事件傳遞非常重要。
依序處理事件,或只處理一次。
為了恢復和延展性,每個取用者類型通常會在多個實例中執行。 如果事件必須依取用者類型內的順序處理,或未實作 等冪訊息處理 邏輯,則此程式可能會建立挑戰。
服務之間的訊息協調。
商務程式通常會有多個服務來發佈和訂閱訊息,以在整個工作負載中達成一致的結果。 您可以使用 工作流程模式, 例如 編舞模式 和 Saga Orchestration ,可靠地管理各種服務的訊息流程。
錯誤處理。
事件驅動架構主要使用異步通訊。 非同步通訊的一個挑戰是錯誤處理。 解決此問題的其中一種方法是使用不同的錯誤處理程序處理器。 當事件取用者遇到錯誤時,它會立即和異步地將錯誤事件傳送至錯誤處理程序處理器,並繼續進行。 錯誤處理常式處理器會嘗試修正錯誤,並將事件傳回原始擷取通道。 但是,如果錯誤處理程式處理器失敗,它可以將錯誤事件傳送給系統管理員,以進行進一步檢查。 如果您使用錯誤處理程式處理器,則重新提交錯誤事件時,會依順序處理錯誤事件。
數據遺失。
異步通訊的另一個挑戰是數據遺失。 如果任何元件在成功處理並交出事件之前當機,然後將事件交給其下一個元件,則會卸除事件,且永遠不會進入最終目的地。 若要將數據遺失的機會降到最低,請保存傳輸中事件,並在下一個元件認可收到事件時移除或清除事件佇列。 這些功能稱為 客戶端認可模式 和 最後一個參與者支援。
實作傳統的要求-回應模式。
有時候事件產生者需要事件取用者的立即回應,例如先取得客戶資格,再繼續進行訂單。 在事件驅動架構中,您可以使用 要求-回應傳訊來達成同步通訊。
此模式通常會使用兩個佇列來實作:要求佇列和回應佇列。 事件產生者會將異步要求傳送至要求佇列、暫停該工作的其他作業,以及等候回復佇列中的回應。 此方法實際上會將此模式轉換成同步程式。 事件取用者接著會處理要求,並透過回應佇列將回復傳回。 這種方法通常會使用會話標識符進行追蹤,因此事件產生者知道回應佇列中的哪一則訊息與特定要求有關。 原始要求也可以指定回應佇列的名稱,可能是暫時的,在 回復標頭 或其他共同同意的自定義屬性中。
維護適當的事件數目。
產生過多的精細事件可能會使系統飽和並壓倒,因此難以有效地分析事件的整體流程。 需要復原變更時,此問題會加劇。 相反地,過度合併事件也可能會造成問題,導致事件取用者不必要的處理和回應。
若要達到正確的平衡,請考慮事件的後果,以及取用者是否需要檢查事件承載以判斷其回應。 例如,如果您有合規性檢查元件,可能就足以只發佈兩種類型的事件: 符合規範 和 不相容。 這種方法有助於確保只有相關的取用者處理每個事件,以避免不必要的處理。
其他考慮
要包含在事件中的資料量可能是影響效能和成本的重要考慮。 您可以簡化處理程序代碼,並排除額外的查閱,方法是直接在 事件中放置處理所需的所有相關信息。 當您將最少的資訊新增至事件時,例如一些標識符,可以降低傳輸時間和成本。 不過,此方法需要處理程式代碼來擷取它所需的任何其他資訊。 如需詳細資訊,請參閱 將您的活動放在飲食上。
要求處理元件只能看見要求。 但是工作負載中的多個元件通常可以看到事件,即使這些元件不是或不是用來取用這些元件也一樣。 若要以「假設缺口」思維運作,請留意您在事件中包含的資訊,以防止意外的資訊暴露。
許多應用程式會使用事件驅動架構作為其主要架構。 您可以將此方法與其他架構樣式結合,以建立混合式架構。 一般組合包括 微服務 和 管道和篩選。 整合事件驅動架構,藉由消除瓶頸並在高要求量期間提供 回溯壓力 來增強系統效能。
特定網域 通常會跨越多個事件產生者、取用者或事件通道。 特定網域的變更可能會影響許多元件。
相關資源
- 社群討論影片,說明在編排與協調流程之間選擇的考慮。