混合雲中的事件驅動架構

2022-07-03 07:39:11 字數 4300 閱讀 1392

譯自:introduction to event-driven architecture

目錄事件處理的方式

什麼時候使用eda

eda的好處

eda的缺點

需要注意的點

總結在前面的微服務介紹一文中討論了服務的顆粒度,以及保證松耦合的必要性。文中提出,服務應該是自治且完整獨立的,並儘量減少同步通訊。今天,我們將討論松耦合意味著什麼,並探索一種在微服務社群中越來越受歡迎的"交易技巧"-事件驅動架構。

事件驅動架構(eda)是乙個促進生產和消費事件的軟體架構規範。

永遠不會發生的事件

關於事件的奇特之處在於它們不會明確地傳達給可能關心它們的特定服務。事件"只會發生"。更為重要的是事件只會單純地發生,與是否存在關心這些事件的特定服務無關。這聽起來像是經常被引用的哲學思想:"如果一顆森林中的樹,沒有人聽到它,那麼它會發出聲音嗎?"。但這也是事件之所以強大的原因--事件會轉換為一條對某些正在發生的事情的(自包含)記錄,事件及其擴充套件程式(從根本上講)與它們的處理程式是分離的。實際上,事件記錄的生產者並不知道消費者是誰,甚至不知道是否存在消費者。

一條記錄通常包含描述乙個事件的資訊。在之前的訂單為例,其對應的事件的json描述如下:

上述是對乙個訂單的高度簡化。發起訂單(購物車服務)的應用並不知道誰(如何,以及為什麼)處理該訂單。生產者會保證潛在的消費者能夠捕獲處理事件所需的一切資訊。也就是說,訂單記錄不一定嚴格包含實現訂單所需的每個屬性。例如,不一定會直接指定產品的尺寸,存放位置以及消費者的送貨位址等資訊,但可以解析通過捕獲的訂單記錄中的id間接獲得這些資訊。關聯式資料庫中的外來鍵概念也同樣適用於事件。

通道傳輸的事件

如果生產者和消費者都互不感知對方,那麼兩者該如何通訊?

答案是通過術語"記錄"進行粘合。事件通常被持久化到乙個眾所周知的位置,稱為日誌(有時也會用到術語"賬簿")。日誌是底層的,只能在後續消費者可以訪問的地方附加生產者儲存的事件資料結構。brokers(位於生產者和消費者之間的持久化中介軟體)負責操作日誌。一旦產生了乙個事件,任何人都可以消費該事件。

當處理事件驅動系統時,我們經常會使用術語"流"來描述乙個或多個日誌介面。日誌是物理上的概念(使用檔案實現),一條流是邏輯上的概念,表示構成事件的一組沒無邊界的記錄,但記錄要遵守某種特定的順序。不同的流平台可能使用專有名稱指代一條流。apache kafka使用topics和partitions來描述流。

生產者、消費者和流的關係如下:

通過非同步性和通用性進行解耦

為什麼eda能夠大大降低耦合度?

對耦合的一種比較務實的定義是:乙個元件受其他元件影響的程度。耦合存在於空間(元件在結構上相關聯)和時間(時間會影響元件之間的關係程度)上。對於後者,乙個比較好的例子是,乙個服務同步呼叫其他服務的rest api。如果被呼叫的服務down,則該服務將無法繼續處理(響應被阻塞)。如果兩個服務必須同時執行,則二者之間會存在一定程度的臨時耦合(temporal coupling)。如果兩個服務高度依賴,則稱之為強耦合,反之,則稱為松耦合。

eda採用兩種方法來抑制耦合。

eda並不是銀彈,它沒有一併消除耦合的概念(否則,系統中的元件將不再共同作用)。現在將關注點轉移到broker上:為了讓生產者和消費者有意義地進行解耦,它們必須依賴乙個broker。這種方式增加了系統架構的複雜度,並引入了其他故障點。這也是為什麼brokers必須是高效能且具有容錯能力,否則,我們只是將一組問題換成另一組。

時間處理通常分為三種常用的方式。這些方式並不互斥,它們經常會同時存在於乙個大型的事件驅動系統中。

離散事件處理

用於處理離散事件:例如在社交**平台上發布乙個帖子。離散事件處理的特徵在於出現的事件之間通常並無關聯,可以獨立處理。

事件流處理

用於處理一系列相關聯的無邊界事件流,事件的記錄以某種順序呈現,並攜帶一些與發生的事件有關的資訊。例如,當乙個業務實體發生聯合變更時,消費者可能會按照生產者指定的順序進行變更,並在本地資料庫中儲存乙份該實體的副本。由於需要關注事件處理的順序,因此不能離散地處理這類事件。消費者需要避免條件競爭,即多個消費者例項可能會同時修改資料庫中的某條記錄,進而由於亂序更新而導致資料不一致。

比較有名的流事件平台,如kafka會依賴記錄的key和partitions來保留更新順序。kafka同時也保證對乙個實體的所有變更會被某個消費者處理,避免多個消費者並行處理事件而導致併發競爭。

複雜事件處理

複雜事件處理(cep)是一種從一系列簡單事件中得出或識別複雜事件的模式。例如監控一座建築內的溫度和延誤感應器,並於推斷是否發生了火情,並進行持續跟蹤。單獨的溫度變化並不足以引發報警。更具意義的是溫度峰值和變化率聚合而成的群體事件,進而有可能挽救生命。

通常更多會涉及此類處理,要求事件處理器持續跟蹤先前的事件,並提供乙個有效的方式進行請求和聚合。

一些場景下可以使用事件驅動架構帶來的優勢:

快取和容錯能力。事件消費的速率可能與生產者不同步,生產者不能為了與消費者保持一致而放慢速率。

生產者和消費者解耦,避免笨拙的點到點整合。eda下很容易新增新的生產者和消費者,也很容易修改生產者和消費者的實現(前提是遵守約束事件記錄的合同/方案)。

大規模擴充套件。通常會把部分部分事件流切分為若干不相關的自流,然後並行處理。隨著事件的積壓,我們也可以擴充套件消費者的數量來滿足負載需求。像kafka這樣的平台會嚴格按序處理事件,並允許跨流進行大規模並行處理。

僅限非同步處理。雖然eda是一種有效的系統解耦模式,但它也將應用限制為非同步事件處理。eda並不能很好地處理像請求響應這樣的互動(發起者必須等待響應才能繼續處理)。

引入額外的複雜度。傳統的客戶端-伺服器以及請求-響應僅會涉及兩方,在採用eda之後則引入了第三方-broker,作為生產者和消費者之間的媒介。

故障掩蓋。這一點比較奇特,因為它似乎與解耦系統的本質背道而馳。當系統高度耦合時,乙個系統中的錯誤會快速傳遞下去,並引起我們的關注。大多數場景下,我們需要避免這種情況:當乙個元件失敗時,盡量減小它對其他元件的影響。故障掩蓋的負面影響是,它會在不經意間隱藏本應引起我們注意的問題。可以通過為每個事件驅動的元件新增實時監控和日誌來解決,但這樣做也帶來了新的複雜度。

eda不是萬能藥,與很多強大的工具一樣,它有可能被錯誤地使用。下面列出的內容不應該被認為是eda的缺點,而應該作為開發人員和架構師在設計和實現事件驅動的系統時應注意的一系列陷阱。

複雜的編排。使用松耦合元件,使用者可能會感到困惑,整個架構看起來像是乙個rube goldburg機器(可以借助下圖理解rube goldburg),整個業務邏輯也被實現為一系列(帶有***的包裝的)事件:乙個元件發起的事件可能觸發另乙個元件發起另乙個事件,然後觸發另乙個元件發起事件,以此類推。這種元件間的互動很快會變得無法理解。

將命令和事件混淆。乙個事件用於單純地描述發生的事情。它不會指定如何處理事件。而乙個命令是針對特定元件的直接指令。由於命令和事件都是某種型別的訊息,非常容易混淆,把命令誤以為是乙個事件。

命令也可以放到eda下,但要分清與事件的區別。命令可能會修改系統狀態,通常會需要回滾方案。

消費者不可知。事件應該以某種方式捕獲相關的屬性,但並不會限制如何處理這些事件。說起來容易,做起來難。有時我們可能會無法獲得足夠的資訊來限制新增到事件記錄的內容(無法確定這些新增到記錄中的資訊是否最終有用)。

個人認為最重要的是上面的第二點,要區分命令和事件。

微服務架構模式是構建更可維護、可擴充套件、更健壯的軟體系統所涉及的難題之一。從問題分解的角度來看,微服務非常棒,但也帶來了很多棘手的問題,其中乙個就是耦合。與一開始相比,隨意將系統拆分為少數微服務的做法可能會使您處於更糟糕的局面。有乙個術語可以對其進行描述"分布一體式"。

為了幫助解決困惑,並定位耦合的問題,我們引入了事件驅動架構。

eda是乙個可以幫助降低系統元件間的耦合的有效工具,它是一種使用生產者、消費者、事件和流進行互動的模型。乙個事件表示乙個感興趣的動作,任何元件都可能非同步地發布和消費事件,而無需感知對方的存在。eda允許元件獨立操作和演化。但它不是解決所有問題的銀彈。eda是乙個不錯的選擇,它帶來的好處大大超過了採用它的成本。可以說,eda是成功部署微服務的必要要素。

軟體架構 事件驅動架構

事件 event 就是狀態的顯著變化,比如說前面提到的客戶下單被執行。從 來分,事件可以分為系統內部事件和外部事件。從型別來分,可以分為業務事件和系統事件。事件驅動架構 event driven architecture,eda 乙個事件驅動框架 eda 定義了乙個設計和實現乙個應用系統的方法學,在...

事件驅動架構要點

設計元件 領域事件定義 domainevent 領域模型支援領域事件處理 domain 事件池 eventrepository persistence 事件分發 eventdispatcher 事件處理器 領域模型 event processor domain 事件同步處理 等待超時控制 如何在超時...

EDA事件驅動架構

事件代表過去發生的事件,事件既是技術架構概念,也是業務概念。以事件為驅動的程式設計模型稱為事件驅動架構eda。eda是一種以事件為媒介,實現元件或服務之間最大松耦合的方式。傳統面向介面程式設計是以介面為媒介,實現呼叫介面者和介面實現者之間的解耦,但是這種解耦程度不是很高,如果介面發生變化,雙方 都需...