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