云計算設計模式(七)——事件獲取模式
使用僅追加存儲到記錄完整一系列描述在一個域上取數(shù)據(jù),而不是存儲僅僅是當前的狀態(tài),從而使存儲區(qū)可以被用來實現(xiàn)該域對象的動作事件。該圖案可以通過避免需要同步的數(shù)據(jù)模型和商業(yè)領域中簡化復雜的結構域的任務;提高性能,可擴展性和響應能力;提供交易數(shù)據(jù)的一致性;并保持完整的審計跟蹤和記錄,可能使補償措施。
背景和問題
大多數(shù)應用程序使用數(shù)據(jù),并在典型的方法是應用到通過更新它作為用戶使用的數(shù)據(jù)保持數(shù)據(jù)的當前狀態(tài)。例如,在傳統(tǒng)的創(chuàng)建,讀取,更新和刪除(CRUD)模型的典型數(shù)據(jù)處理將是從存貯器中讀出的數(shù)據(jù),進行一些修改,以使其和更新的數(shù)據(jù)的當前狀態(tài)與新的值時─常常通過使用鎖定數(shù)據(jù)的事務。
CRUD 方法有一定的局限性:
- 在 CRUD 系統(tǒng)直接執(zhí)行更新操作對數(shù)據(jù)存儲可能會影響性能和響應能力,并限制可擴展性,因為它需要處理開銷的事實。
- 在具有許多并發(fā)用戶的協(xié)作域,數(shù)據(jù)更新沖突更可能發(fā)生,因為在更新操作發(fā)生在數(shù)據(jù)的單個項目。
- 除非有另外的審核機制,它記錄在一個單獨的日志的每個操作的詳細內(nèi)容,歷史記錄丟失。
注意: 對于的 CRUD 方法的局限性有了更深的了解請參見“CRUD,只有當你能負擔得起”MSDN 上。
解決方案
事件獲取模式定義了一個方法來處理操作上是受一個事件序列,其中的每一個記錄在僅追加存儲驅動的數(shù)據(jù)。應用程序代碼發(fā)送一系列命令性描述上發(fā)生的數(shù)據(jù)的情況下存儲,在那里它們被持久保存的每個動作的事件。每個事件都表示一組數(shù)據(jù)更改(如 AddedItemToOrder)的。
事件持久保存在一個事件存儲在充當真理或記錄的系統(tǒng)的源(權威數(shù)據(jù)源給定的數(shù)據(jù)元素或信息)有關的數(shù)據(jù)的當前狀態(tài)。事件存儲通常發(fā)布這些事件讓消費者能夠得到通知,如果需要,可以處理它們。消費者可以,例如,啟動該應用中的事件的動作的其他系統(tǒng)的任務或執(zhí)行完成操作所需的任何其他相關聯(lián)的動作。注意,生成該事件的應用程序代碼從訂閱該事件的系統(tǒng)去耦。
在事件存儲公布了事件的典型用途是保持實體化視圖的應用程序中的行動改變他們,并與外部系統(tǒng)的集成。例如,系統(tǒng)可保持用于填充UI部分的客戶訂單的實體化視圖。隨著應用增加了新的訂單,增加或訂單上刪除的項目,并增加了發(fā)貨信息,描述這些變化可以被處理和使用的事件來更新物化視圖。
此外,在任何時間點,可以對應用程序來讀取事件的歷史,并使用它通過有效地“回放”和消耗所有有關該實體的事件,以實現(xiàn)一個實體的當前狀態(tài)。這可能發(fā)生在需求,以處理時的要求,或通過計劃任務,使該實體的狀態(tài)可以被保存為一個物化視圖,以支持表示層來實現(xiàn)域對象。
圖1示出的圖案的邏輯的概述,包括一些使用事件流,例如,創(chuàng)建的物化視圖,與外部應用程序和系統(tǒng)整合事件,并重放事件來創(chuàng)建特定實體的當前狀態(tài)的突起的選項。
圖1 - 的情況下獲取模式的概述和示例
事件獲取模式提供了許多優(yōu)點,包括如下:
- 活動是不可變的,因此可以使用僅追加操作來保存。用戶界面,工作流或過程發(fā)起產(chǎn)生該事件可以繼續(xù),并且處理這些事件可以在后臺運行的任務的操作。此,結合的事實,有記錄的執(zhí)行過程中沒有爭用,可以極大地提高性能和可擴展性的應用,尤其是對于表示層或用戶界面。
- 活動是描述所發(fā)生的一些動作,再加上描述的事件所代表的行動所需的任何相關數(shù)據(jù)的簡單對象。事件不直接更新數(shù)據(jù)存儲;它們被簡單地記錄用于處理在適當?shù)臅r間。這些因素可以簡化實施和管理。
- 活動通常意味著一個領域的專家,而對象關系的阻抗失配的復雜性可能意味著一個數(shù)據(jù)庫表可能無法清楚地了解該領域的專家。表是表示該系統(tǒng)中,未發(fā)生的事件的當前狀態(tài),人工構建體。
- 事件的采購可以幫助防止引起沖突,因為它避免了要求直接更新在數(shù)據(jù)存儲對象的并發(fā)更新。然而,領域模型仍然必須用來保護自己免受可能導致不一致的狀態(tài)的請求。
- 事件的僅追加存儲提供了可用于監(jiān)測對一個數(shù)據(jù)存儲所采取的行動的審核跟蹤,??再生的當前狀態(tài)作為通過重播事件隨時物化視圖或預測,并協(xié)助測試和調(diào)試系統(tǒng)。此外,該規(guī)定使用補償事件取消變化提供了被逆轉的變化,這不會是如果模型簡單地存儲在當前狀態(tài)的情況下的歷史記錄。事件列表中,也可以用于分析應用程序的性能,并檢測用戶行為趨勢,或獲得其它有用的商業(yè)信息。
- 從響應進行操作的事件存儲提出的每個事件的任何任務事件的解耦提供了靈活性和可擴展性。例如,用于處理由所述事件存儲引發(fā)的事件的任務都知道只有事件的性質(zhì)和它包含的數(shù)據(jù)。時所執(zhí)行的任務的方式是從觸發(fā)事件的動作去耦。此外,多個任務可以處理每個事件。這可能使得與其他服務和系統(tǒng),只需要監(jiān)聽的事件存儲提出了新的事件,易于集成。然而,該事件采購事件往往是非常低的水平,并且可能有必要以產(chǎn)生特異性整合事件來代替。
注意: 事件來源通常結合 CQRS 模式通過執(zhí)行數(shù)據(jù)管理任務響應于所述事件,并通過物化從所存儲的事件的意見。
問題和注意事項
在決定如何實現(xiàn)這個模式時,請考慮以下幾點:
- 創(chuàng)建物化視圖或重放事件產(chǎn)生的數(shù)據(jù)的預測時,系統(tǒng)只會是最終一致。有一個應用程序添加事件,事件存儲作為處理一個請求的結果之間有一些延遲,被公布事件,而消費者對事件的處理它們。在此期間,描述該進一步修改實體的新的事件可能已到達的情況下存儲。
注意: 請參閱數(shù)據(jù)一致性底漆有關最終一致性的信息。
- 事件存儲是信息不可變源,因此事件數(shù)據(jù)不應該被更新。要以撤銷變更更新一個實體的唯一辦法是補償?shù)氖录砑拥绞录鎯?,就像你會用負?shù)交易的會計核算。如果持久化事件的格式(而不是數(shù)據(jù))需要改變,或者在遷移過程中,可能難以對現(xiàn)有的事件結合在商店的新版本??赡苡斜匾ㄟ^所有更改的事件來循環(huán)以使它們符合新格式,或添加使用該新格式的新事件。考慮使用上的每個版本的事件模式的版本標記,以保持舊的和新的事件格式。
- 多線程應用程序和應用程序的多個實例可以被存儲在事件存儲事件。在事件存儲事件的一致性是非常重要的,是影響到特定實體(的順序改變?yōu)橐粋€實體發(fā)生影響其當前狀態(tài))的事件的順序。添加時間戳到每一個事件是一個選項,可以幫助避免出現(xiàn)問題。另一種常見的做法是將注釋每一個事件所導致使用增量標識符的請求。如果兩個動作試圖為同一實體的同時添加的事件,該事件存儲可以拒絕匹配現(xiàn)有實體標識符和事件標識符事件。
- 有沒有標準的方法,還是準備建機制,如 SQL 查詢,讀取事件來獲取信息??梢蕴崛〉奈ㄒ粩?shù)據(jù)是使用事件標識符作為條件的事件流。事件ID通常映射到單個實體。一個實體的當前狀態(tài),可以僅通過重放所有涉及到它針對該實體的原始狀態(tài)的事件的確定。
- 每個事件流的長度可以有上管理并更新該系統(tǒng)的后果。如果流很大,可以考慮創(chuàng)建以特定的間隔的快照,如活動指定數(shù)量??梢詮脑摽煺?,通過重放該時間點之后發(fā)生的任何事件中得到的實體的當前狀態(tài)。
注意: 有關創(chuàng)建數(shù)據(jù)快照的更多信息,請參見Martin Fowler的企業(yè)應用架構的網(wǎng)站和主從快照復制MSDN上的快照。
- 盡管采購活動減少沖突的更新數(shù)據(jù)的機會,應用程序必須仍然能夠應付可能出現(xiàn)的通過最終一致性和缺乏交易的不一致。例如,一個事件,指示庫存的庫存的減少可能在數(shù)據(jù)存儲到達,而對于該產(chǎn)品的訂單被放置,從而導致需求調(diào)和這兩種業(yè)務;可能是建議客戶或創(chuàng)建后順序。
- 事件發(fā)布可能是“至少一次”等消費者的事件,必須冪等。它們不能重新在一個事件描述,如果該事件被處理多于一次的更新。例如,如果一消費者的多個實例保持一些實體的一個屬性的集合,如訂單放置的總數(shù)中,只有一個必須在當一個“順序放置”事件發(fā)生時,遞增該聚合成功。雖然這不是事件來源的固有特性,它是通常的實現(xiàn)決策。
當使用這個模式
這種模式非常適合以下情況:
- 當你想捕捉“意圖”,“目的”或“理”中的數(shù)據(jù)。例如,如動家,已關閉帳戶,或已故變?yōu)橐粋€客戶實體可被捕捉為一系列特定的事件類型。
- 當它是至關重要的,盡量減少或完全避免更新沖突的發(fā)生數(shù)據(jù)。
- 當你想記錄發(fā)生的事件,并能夠重放它們來恢復系統(tǒng)的狀態(tài);用它們來回滾更改的系統(tǒng);或者簡單地作為一個歷史和審計日志。例如,當一個任務涉及多個步驟,您可能需要執(zhí)行恢復更新操作,然后重放一些步驟,使數(shù)據(jù)恢復到一致狀態(tài)。
- 當使用事件是應用程序的動作的自然特征,并且需要很少的額外的開發(fā)或實現(xiàn)工作。
- 當您需要輸入分離或應用這些行動所需的任務更新數(shù)據(jù)的過程。這可能是為了提高用戶界面的性能,或分發(fā)事件到其它聽眾如其他應用程序或服務,必須采取某些行動的事件發(fā)生時。一個例子是有費用提交網(wǎng)站整合了工資制度,使響應的費用提交網(wǎng)站做數(shù)據(jù)的更新提出的事件存儲事件由兩個網(wǎng)站和工資系統(tǒng)消耗。
- 當您想要的靈活性,能夠改變實體化模型和實體數(shù)據(jù)的格式,如果需求發(fā)生變化,或者,當結合使用 CQRS,你需要適應的讀模式或公開數(shù)據(jù)的意見。
- 與 CQRS 一起使用時,和最終一致性是可以接受的,而讀出的模型被更新,或者,在從事件流中再水化的實體和數(shù)據(jù)發(fā)生的性能的影響是可以接受的。
這種模式可能不適合于下列情況:
- 小型或簡單的領域,很少或沒有業(yè)務邏輯,或者非域系統(tǒng),自然與傳統(tǒng)的 CRUD 的數(shù)據(jù)管理機制,運作良好的系統(tǒng)。
- 哪里的一致性和實時更新數(shù)據(jù)的意見是必需的系統(tǒng)。
- 不要求系統(tǒng)中的審計跟蹤,歷史,功能,回滾和回放操作。
- 系統(tǒng)中只有非常低的沖突更新到基礎數(shù)據(jù)的發(fā)生。例如,主要為添加數(shù)據(jù)而不是更新它的系統(tǒng)。
例子
的會議管理系統(tǒng)需要跟蹤會議完成了預定的數(shù)量,以便它可以檢查是否有座位仍然可用時,一個潛在的與會者試圖做一個新的預訂。該系統(tǒng)可以存儲預定的總數(shù)為在至少兩個方面的會議:
- 該系統(tǒng)可以存儲關于預約的總數(shù)作為數(shù)據(jù)庫中的該擱置預約信息的獨立的實體的信息。作為預訂制成或取消訂單,則系統(tǒng)可以增加或減少該數(shù)量適當。這種方法在理論上是簡單的,但可引起可擴展性問題,如果有大量的與會者試圖進行預訂時的短時間內(nèi)座位。例如,在最后一天或預約期間閉合,以便之前。
- 該系統(tǒng)可以存儲大約預訂和取消如在事件存儲舉辦的活動信息。然后,它可以計算出可用通過重播這些事件的席位數(shù)。這種方法可以更加擴展性由于事件的不變性。該系統(tǒng)只需要能夠從事件存儲讀取數(shù)據(jù),或將數(shù)據(jù)追加到該事件存儲。關于預訂和取消事件信息不會被修改。
圖2顯示了如何將會議管理系統(tǒng)的座位子系統(tǒng)可能通過采購活動來實現(xiàn)。
圖2 - 使用事件來源獲取關于座位預訂信息,在會議管理系統(tǒng)
行動預留兩個座位的順序如下:
1.用戶界面發(fā)出命令,以預留座位有兩個人參加。該命令是由一個單獨的命令處理程序(一塊邏輯的是從用戶界面分離,并負責張貼的命令處理請求)處理。 包含所有預訂的會議信息
2.一種聚集通過查詢描述預訂和取消的事件構成。該集合體被稱為 SeatAvailability,并且被包含在暴露在聚合查詢和修改的數(shù)據(jù)的方法的域模型。
注意: 一些優(yōu)化利用快照(這樣就不需要查詢和重放事件的完整列表,以獲得聚集的當前狀態(tài)),并維持聚合的在存儲器中的高速緩存副本來考慮。
3,命令處理程序調(diào)用的域模型曝光,使保留的方法。
4.SeatAvailability 骨料記錄包含的席位被保留數(shù)量的事件。聚合應用事件接下來的時間,所有的預訂將被用來計算的座位有多少仍然存在。
5.系統(tǒng)追加了新的事件在事件存儲的事件列表。
如果一個用戶希望取消一個座位,該系統(tǒng)遵循不同的是,命令處理程序發(fā)出,其生成一個座位取消事件,并將其追加到事件存儲區(qū)中的命令類似的過程
以及可擴展性提供更大的空間,使用事件店內(nèi)還提供了一個完整的歷史,或審計追蹤,預訂和取消了會議。記錄在事件存儲在事件真相的權威和唯一來源。沒有必要持續(xù)聚集體中的任何其他方法,因為該系統(tǒng)可以很容易地重放這些事件和恢復狀態(tài),以任意的時間點。
更多建議: