事件驅動架構(翻譯)

事件驅動的架構模式時一個非常流行的分佈式異步架構模式,通常用來生成高擴展性的應用。它的適應性非常強,可以用在小應用也可以用在大的複雜的應用上。事件驅動的架構是由高度解耦、單目的的事件處理單元組成,這些單元異步地接受和處理事件。

時間驅動架構模式主要由兩種拓撲結構組成,中繼器與代理。如果你需要把一個事件中各個步驟通過中央中繼器組合起來,那麼就使用中繼器拓撲結構。當你不想有中央中繼器,而是將各個步驟串起來,就使用代理拓撲結構。因爲不同拓撲結構的特性和實現區別挺大,所以有必要搞清楚這兩者來選擇最適合應用的結構。

中繼器拓撲

如果事件有許多步驟而且需要有效的組合在一起來處理事件,中繼器拓撲會很實用。舉例來說,一個單一的事件,完成證券交易,這個事件需要你首先驗證這個交易,然後檢查交易的合規性,再講交易委託給代理,計算佣金,最終通過代理完成交易。所以這些步驟都需要有效的組合,來決定步驟的順序,以及哪些步驟應該串行,哪些該並行。

中繼器拓撲主要有四種不同的架構組成部分:事件隊列,事件中繼器,事件通道,事件處理器。事件流從一個客戶端發送事件到事件隊列開始,事件隊列將事件傳給中繼器。中繼器接受最初事件然後將事件分解成各個步驟,發送到不痛的事件通道來執行每一步。事件處理器,會監聽事件通道,從事件中繼器接受事件並執行具體的業務邏輯。圖2-1說明了事件驅動的中繼器拓撲結構。

在事件驅動架構中,通常有十幾到幾百個事件隊列。事件隊列的實現並沒有限制,可以是一個消息隊列,一個wed服務端點,或者是他們的組合。

在這種模式下,有兩類事件:初始事件和待處理事件。初始事件是中繼器接受的原始事件,而待處理事件是由中繼器生成並由事件處理單元接收。

事件中繼器負責組織初始事件包含的步驟。對每一個步驟,中繼器會發送一個特定的待處理事件到事件通道,然後待處理事件會被事件處理器接收並處理。需要重點關注的是,中繼器並不直接執行處理初始事件的業務邏輯,而是將初始事件分爲幾個步驟。

事件通道是中繼器用來給事件處理器異步發送待處理事件的,這些待處理事件是初始事件經過中繼器生成的。事件通道可以是消息隊列或者消息主題,待處理事件被多個事件處理器處理(每個處理器根據接收的事件處理不同的任務)。

事件處理器包含對事件處理的業務邏輯。事件處理器是獨立的、互不依賴的、高度解耦的結構,處理應用中某個具體的任務。儘管時間處理器的粒度可能從很精細(根據書序計算商業稅)到很粗糙(處理一項保險申購),還是要注意大體上,每個事件處理器都應該執行不同的任務而且不應該依賴其他的處理器來完成它自身的任務。

事件中繼器可以通過各種各樣的方法來實現。作爲一個架構師,我們應該理解每一種實現來確保我們選擇的方案是最適應應用場景的。

最簡單常見的事件中繼器實現方案是開元的集成蜀繡,比如Spring Integration, Apache Camel, 或Mule ESB。這些開元集成樞紐的事件流通常是用Java或DSL實現的。對於更復雜的中繼器和組合方法,可以用BPEL(business process execution language)耦合一個BPEL引擎比如開元的Apache ODE。BPES是一個像XML一樣的標準語言,它描述可以描述處理初始事件的數據和步驟。對非常大型的應用來說,如果包含非常複雜的組合(保羅需要人爲干預的步驟),可以用一個BPM比如jBPM來實現。

理解需求畢竟找到最適合場景的中繼器實現,是中繼器拓撲結構最重要的事情。使用一個開源的基礎樞紐來進行非常複雜的業務處理管理是失敗的,就想使用BPM來處理非常簡單的邏輯,一樣也是失敗的。

爲了說明中繼器邏輯是如何工作的,假設你已經被保險公司確認投保,然後你決定執行。在這個例子中,初始事件可以稱作「重定位事件」。圖2-2表明了中繼器怎麼處理一個重定位事件。對每個初始事件步驟,事件中繼器會創建一個待處理事件(比如修改地址,重新計算報價等),將待處理事件發送給事件通道並等待事件通道被相應的事件處理器處理。這個處理會一直持續知道所有的初始事件被處理完畢。重新計算報價和更新理賠的步驟,是可以同時異步執行的。

代理人拓撲

代理人拓撲和中繼器拓撲最大的區別是代理人沒有中央事件中繼器;小溪流像鏈條一樣分佈到事件處理器中,這過程由一個輕量級的消息代理(如ActiveMQ,HornetQ等)完成。當你需要一個相對簡單的事件處理過程而且你不需要中央組成器的時候,這種拓撲結構就會非常有用。

代理人拓撲也有兩類主要的成分:代理人和事件處理器。代理人組件可以是集中式或聯邦式的,而且包含所有事件流中用到的的事件通道。這些事件通道可以是消息隊列,消息主體或者兩者結合。

圖2-3就是代理人拓撲結構。可以從圖表中看出,沒有中央事件中繼器組件控制和組合初始事件;二是每個事件處理器組件負責處理一個事件並且發佈一個新的事件來說明它剛纔執行的動作。舉例來說,一個事件處理器比如平衡一個證券投資組合,可能會接受一個叫做股票拆分的初始事件。基於這個初始事件,事件處理器會做一些投資組合調整,然後發佈一個新的事件「調整投資組合」給代理人,這個事件會被另外一個不同的事件處理器接收。注意到會有一個事件被髮出來後沒有被另一個事件處理器接收的情況發生。這通常發生在你給應用升級或者提供一些未來的功能和拓展的時候。

 

爲了說明代理人拓撲的工作方式,我們使用和中繼器拓撲一樣的例子(一個確認投保的人搬家)來說。因爲代理人拓撲沒有一箇中央事件中繼器來接收初始事件,消費者處理組件直接接收這個事件,改變消費者的地址(如 地址變更事件)。在這個例子中,有兩個事件處理器對地址變更事件感興趣:報價處理和理賠處理。報價處理器根據地址變更重新計算新的汽車保險賠率,併發佈一個事件告訴其他處理器它所做的事情。理賠處理組件,另一方面,接收同樣的地址變更事件,但是它會更新一個沒有理賠的保險併發佈一個新的事件「更新理賠」到系統中去。這些新的事件會被其他事件處理組件接收,而且這個鏈式的系統會一直進行直到沒有和初始事件有關的事件產生。

從圖2-4中可以看到,代理人拓撲所有都是有關業務邏輯處理的整個過程。最好的理解方式就是把它想象成一個接力賽。在接力賽中,運動員拿着一個接力棒然後跑一段固定的距離,然後將接力棒交給下一個運動員,依次進行知道最後一個運動員衝過終點。在接力賽中,一旦運動員交接完接力棒,他就和接力賽無關了。這對代理人拓撲也是適用的:一旦一個事件處理器交接了事件,它就不會再參與到這個事件的處理過程中。

思考

事件驅動架構模式實現起來相對來說比較複雜,根本上是因爲它的異步分佈式本質。當我們實現這個模式時,一定要處理各種各樣的分佈式架構的問題,比如遠程處理能力,相應的缺乏,以及代理或中繼器失敗後的重連邏輯。

一個需要考慮的點是當選擇這種模式時,需要考慮單個業務處理之間的原子性。因爲事件處理器是高度解耦和分佈的所以很難維持一個工作的食物單元。出於這個原因,在使用這種模式設計應用時,一定要持續思考哪些事件可以或不可以獨立執行,以及根據事件來設置事件處理器的粒度。如果需要將單一工作拆分到多個事件處理器中,即需要強行把一個能單獨處理的事物拆分到多個事件處理器,那麼可能不太適合這種模式。

也許事件驅動最難的部分是事件處理器組件數據結構的創造、維護和管理。每個事件通常都有一個特定的結構(如 傳給處理器的數據值和數據格式)。當使用這種模式時,選定一個標準的數據格式非常重要,然後從一開始就建立數據結構的控制。

模式分析

全局靈活性

評分:高

分析:全局靈活性是對持續變化的環境做出快速響應的能力。由於事件驅動組件都是單一目的而且和其他處理器是完全解耦的,所以改變也會隔離在一個或少數處理器中因此使得它能夠快速的對改變做出應對且不影響其他組件。

部署容易程度

評分:高

分析:總體來說這種模式相對來說是比較容易部署的,因爲各個事件處理器天然是解耦的。代理人拓撲比中繼器拓撲更容易部署,主要是因爲中繼器拓撲有中央中繼器,中繼器和事件處理器都和中央中繼器耦合,所以事件處理器的改變可能也會引起事件中繼器的改變,兩者都需要重新部署。

可測試性

評分:低

分析:儘管獨立單元測試總體來說並不難,也不需要一些特定的客戶端或工具來獲得測試結果。但是由於這種模式的異步天性,測試還是一件複雜的事情。

性能

評分:高

分析:儘管由於事件驅動架構包含一個消息隊列結構,會造成這種架構性能的下降,但是通常,由於異步特性,這種模式還是具有非常高的性能。換句話說異步和解耦分佈式帶來的好處比消息隊列帶來的壞處要大。

可擴展性

評分:高

分析:擴展性是這種架構模式的天性,因爲整個架構都是解耦的,分佈式的。每個事件處理器都可以獨立的擴展。

開發容易程度

評分:低

分析:由於異步特性,這種模式開發起來可能不那麼容易。