<sub id="gqw76"><listing id="gqw76"></listing></sub>
      <sub id="gqw76"><listing id="gqw76"></listing></sub>

    1. <form id="gqw76"><legend id="gqw76"></legend></form>
    2. 介紹基于事件的架構

      介紹基于事件的架構

      譯自:Introduction to Event-Driven Architecture

      后面將引入幾篇與EDA相關的文章,目的在于充分掌握EDA架構的優劣勢。

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

      簡單定義

      事件驅動架構(EDA)是一個促進生產和消費事件的軟件架構規范。

      一個事件表示一個感興趣的動作。通常,事件對應一個創建或修改某些實體狀態的動作。例如,在電子商務應用程序中下訂單是一個事件,分發一個已下單的產品也是一個事件。一個消費者提交一個對接收的產品的評論也是一個事件。

      永遠不會發生的事件

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

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

      {
        "orderId": "760b5301-295f-4fec-95f8-6b303a3b824a",
        "customerId": 28623823,
        "productId": 31334,
        "quantity": 1,
        "timestamp": "2021-02-09T11:12:17+0000"
      }
      

      Node:盡管記錄和事件存在細微的差別,但它們經常可以互換,即術語"事件"通常指代一個事件的"記錄",為了簡化描述,本文中將自由地使用這兩個術語。

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

      通道傳輸的事件

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

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

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

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

      Event-Driven Architecture Reference Model

      回顧一下相關概念:

      • 事件是在離散時間點發生的感興趣的動作:可能從外部對其進行觀察和描述。
      • 事件持久化為記錄:事件和記錄盡管是相關的,但在技術上是不同的。一個事件表示事情的發生(如狀態變更),本身是無形的。而一條記錄是對該事件的精確描述。我們通常使用術語"事件"來指代其對應的記錄。
      • 生產者是通過將相應的記錄發布到流中來檢測事件的接收器。(發布一條記錄則表示發生了一個事件)
      • 流是持久化的有序的記錄。它們通常由一個或多個基于磁盤的日志來進行持久化,當然,也可以使用數據庫表、分布式共識協議,甚至是區塊鏈式的分散賬本來支持持久化。
      • Brokers 負責對流的訪問,方便讀寫操作,處理消費者狀態以及在流上執行各種"內務"。例如,一個broker可能在記錄溢出時對流的內容進行截取。
      • 消費者讀取流,然后對接收到的記錄作出回應。消費者對事件的回應可能會伴隨一些額外的操作。例如,一個消費者可能會在本地數據庫中持久化一條表項(通過發布的"更新"事件來重構遠端實體的狀態)(即更新對遠端實體的描述)。
      • 消費者和生產者可能會重疊。例如,對事件的回應方,也可能產生一個或多個派生的事件。

      通過異步性和通用性進行解耦

      為什么EDA能夠大大降低耦合度?

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

      Conceptual model of coupling

      EDA采用兩種方法來抑制耦合。

      • 回顧一下,事件是不能通信的,它們只會發生。發起事件的組件(通過發布記錄)并不知道其他組件是否存在。因此,即使消費者不可用,生產者也不會停止工作---broker會暫時緩存事件,而不會對生產者施加反向壓力。
      • broker對事件記錄的持久化大大消除了時間觀念。一個生產者可能會在T1時間發布一個事件,而一個消費者可能會在T2事件才會讀取該事件,T1T2之間的間隔可能是毫秒級別的(所有組件正常)或小時級別的(如果某些消費者down或忙于其他事情)。

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

      事件處理的方式

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

      離散事件處理

      用于處理離散事件:例如在社交媒體平臺上發布一個帖子。離散事件處理的特征在于出現的事件之間通常并無關聯,可以獨立處理。

      事件流處理

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

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

      復雜事件處理

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

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

      什么時候使用EDA

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

      • 不透明的消費者生態系統。這種情況下,生產者并不了解消費者,后者可能是一個短暫的過程,可能在短時間內來來往往!
      • 高扇出。一個事件可能由多個不同的消費者處理的場景。
      • 復雜的模式匹配。可能將事件串在一起來推斷出更復雜的事件。(這類場景可能需要進行匯總,即上面描述的復雜事件處理)
      • 命令查詢的責任分離。CQRS是一種分離數據存儲區的讀取和更新操作的模式。實現CQRS可以提高應用的可擴展性和彈性(在數據一致性上進行了取舍)。 這種模式通常與EDA相關。

      EDA的好處

      1. 緩存和容錯能力。事件消費的速率可能與生產者不同步,生產者不能為了與消費者保持一致而放慢速率。
      2. 生產者和消費者解耦,避免笨拙的點到點集成。EDA下很容易添加新的生產者和消費者,也很容易修改生產者和消費者的實現(前提是遵守約束事件記錄的合同/方案)。
      3. 大規模擴展。通常會把部分部分事件流切分為若干不相關的自流,然后并行處理。隨著事件的積壓,我們也可以擴展消費者的數量來滿足負載需求。像Kafka這樣的平臺會嚴格按序處理事件,并允許跨流進行大規模并行處理。

      EDA的缺點

      1. 僅限異步處理。雖然EDA是一種有效的系統解耦模式,但它也將應用限制為異步事件處理。EDA并不能很好地處理像請求響應這樣的交互(發起者必須等待響應才能繼續處理)。
      2. 引入額外的復雜度。傳統的客戶端-服務器以及請求-響應僅會涉及兩方,在采用EDA之后則引入了第三方-broker,作為生產者和消費者之間的媒介。
      3. 故障掩蓋。這一點比較奇特,因為它似乎與解耦系統的本質背道而馳。當系統高度耦合時,一個系統中的錯誤會快速傳遞下去,并引起我們的關注。大多數場景下,我們需要避免這種情況:當一個組件失敗時,盡量減小它對其他組件的影響。故障掩蓋的負面影響是,它會在不經意間隱藏本應引起我們注意的問題。可以通過為每個事件驅動的組件添加實時監控和日志來解決,但這樣做也帶來了新的復雜度。

      需要注意的點

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

      1. 復雜的編排。使用松耦合組件,用戶可能會感到困惑,整個架構看起來像是一個Rube Goldburg機器(可以借助下圖理解Rube Goldburg),整個業務邏輯也被實現為一系列(帶有副作用的包裝的)事件:一個組件發起的事件可能觸發另一個組件發起另一個事件,然后觸發另一個組件發起事件,以此類推。這種組件間的交互很快會變得無法理解。

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

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

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

      個人認為最重要的是上面的第二點,要區分事件和命令。事件是已經發生的操作,而命令表示正在處理中的操作(未完成或失敗)。消息隊列通常用于處理命令,而kafka則被設計來處理事件,當然這類處理方式在分布式事務中稱為MQ事務

      總結

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

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

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

      本文主要描述了EDA中的事件的本質,以及對事件的處理邏輯,事件可以是離散的,也可以是有順序的。除事件外EDA其實也可以處理命令和查詢請求,但要針對各自的特性和業務邏輯進行針對性的處理。除此之外還應該注意到EDA的局限性,避免不合時宜地使用EDA。

      在分布式環境中,一個比較難處理的問題是分布式事務,通常指數據庫事務。分布式事務選型一般涉及2PC、3PC、TCC、SAGA、以及Seata。沒有完美的分布式事務解決方案,它們不過是各自在性能、一致性、可用性等方面做取舍,尋求某些場景偏好下的權衡。

      參考:

      posted @ 2021-03-01 16:34  charlieroro  閱讀(265)  評論(0編輯  收藏
      最新chease0ldman老人|无码亚洲人妻下载|大香蕉在线看好吊妞视频这里有精品www|亚洲色情综合网

        <sub id="gqw76"><listing id="gqw76"></listing></sub>
        <sub id="gqw76"><listing id="gqw76"></listing></sub>

      1. <form id="gqw76"><legend id="gqw76"></legend></form>