鍍金池/ 教程/ 大數(shù)據(jù)/ 事件獲取模式
索引表模式
Sharding 分片模式
外部配置存儲(chǔ)模式
命令和查詢(xún)職責(zé)分離(CQRS)模式
靜態(tài)內(nèi)容托管模式
運(yùn)行重構(gòu)模式
計(jì)算資源整合模式
Throttling 節(jié)流模式
斷路器模式
事件獲取模式
實(shí)體化視圖模式
緩存預(yù)留模式
守門(mén)員模式
聯(lián)合身份模式
補(bǔ)償交易模式
重試模式
領(lǐng)導(dǎo)人選舉模式
優(yōu)先級(jí)隊(duì)列模式
健康端點(diǎn)監(jiān)控模式
消費(fèi)者的競(jìng)爭(zhēng)模式
基于隊(duì)列的負(fù)載均衡模式
仆人鍵模式
管道和過(guò)濾器模式
調(diào)度程序代理管理者模式

事件獲取模式

使用僅追加存儲(chǔ)到記錄完整一系列描述在一個(gè)域上取數(shù)據(jù),而不是存儲(chǔ)僅僅是當(dāng)前的狀態(tài),從而使存儲(chǔ)區(qū)可以被用來(lái)實(shí)現(xiàn)該域?qū)ο蟮膭?dòng)作事件。該圖案可以通過(guò)避免需要同步的數(shù)據(jù)模型和商業(yè)領(lǐng)域中簡(jiǎn)化復(fù)雜的結(jié)構(gòu)域的任務(wù);提高性能,可擴(kuò)展性和響應(yīng)能力;提供交易數(shù)據(jù)的一致性;并保持完整的審計(jì)跟蹤和記錄,可能使補(bǔ)償措施。

背景和問(wèn)題

大多數(shù)應(yīng)用程序使用數(shù)據(jù),并在典型的方法是應(yīng)用到通過(guò)更新它作為用戶使用的數(shù)據(jù)保持?jǐn)?shù)據(jù)的當(dāng)前狀態(tài)。例如,在傳統(tǒng)的創(chuàng)建,讀取,更新和刪除(CRUD)模型的典型數(shù)據(jù)處理將是從存貯器中讀出的數(shù)據(jù),進(jìn)行一些修改,以使其和更新的數(shù)據(jù)的當(dāng)前狀態(tài)與新的值時(shí)─常常通過(guò)使用鎖定數(shù)據(jù)的事務(wù)。

CRUD 方法有一定的局限性:

  • 在 CRUD 系統(tǒng)直接執(zhí)行更新操作對(duì)數(shù)據(jù)存儲(chǔ)可能會(huì)影響性能和響應(yīng)能力,并限制可擴(kuò)展性,因?yàn)樗枰幚黹_(kāi)銷(xiāo)的事實(shí)。
  • 在具有許多并發(fā)用戶的協(xié)作域,數(shù)據(jù)更新沖突更可能發(fā)生,因?yàn)樵诟虏僮靼l(fā)生在數(shù)據(jù)的單個(gè)項(xiàng)目。
  • 除非有另外的審核機(jī)制,它記錄在一個(gè)單獨(dú)的日志的每個(gè)操作的詳細(xì)內(nèi)容,歷史記錄丟失。

注意: 對(duì)于的 CRUD 方法的局限性有了更深的了解請(qǐng)參見(jiàn)“CRUD,只有當(dāng)你能負(fù)擔(dān)得起”MSDN 上。

解決方案

事件獲取模式定義了一個(gè)方法來(lái)處理操作上是受一個(gè)事件序列,其中的每一個(gè)記錄在僅追加存儲(chǔ)驅(qū)動(dòng)的數(shù)據(jù)。應(yīng)用程序代碼發(fā)送一系列命令性描述上發(fā)生的數(shù)據(jù)的情況下存儲(chǔ),在那里它們被持久保存的每個(gè)動(dòng)作的事件。每個(gè)事件都表示一組數(shù)據(jù)更改(如 AddedItemToOrder)的。

事件持久保存在一個(gè)事件存儲(chǔ)在充當(dāng)真理或記錄的系統(tǒng)的源(權(quán)威數(shù)據(jù)源給定的數(shù)據(jù)元素或信息)有關(guān)的數(shù)據(jù)的當(dāng)前狀態(tài)。事件存儲(chǔ)通常發(fā)布這些事件讓消費(fèi)者能夠得到通知,如果需要,可以處理它們。消費(fèi)者可以,例如,啟動(dòng)該應(yīng)用中的事件的動(dòng)作的其他系統(tǒng)的任務(wù)或執(zhí)行完成操作所需的任何其他相關(guān)聯(lián)的動(dòng)作。注意,生成該事件的應(yīng)用程序代碼從訂閱該事件的系統(tǒng)去耦。

在事件存儲(chǔ)公布了事件的典型用途是保持實(shí)體化視圖的應(yīng)用程序中的行動(dòng)改變他們,并與外部系統(tǒng)的集成。例如,系統(tǒng)可保持用于填充UI部分的客戶訂單的實(shí)體化視圖。隨著應(yīng)用增加了新的訂單,增加或訂單上刪除的項(xiàng)目,并增加了發(fā)貨信息,描述這些變化可以被處理和使用的事件來(lái)更新物化視圖。

此外,在任何時(shí)間點(diǎn),可以對(duì)應(yīng)用程序來(lái)讀取事件的歷史,并使用它通過(guò)有效地“回放”和消耗所有有關(guān)該實(shí)體的事件,以實(shí)現(xiàn)一個(gè)實(shí)體的當(dāng)前狀態(tài)。這可能發(fā)生在需求,以處理時(shí)的要求,或通過(guò)計(jì)劃任務(wù),使該實(shí)體的狀態(tài)可以被保存為一個(gè)物化視圖,以支持表示層來(lái)實(shí)現(xiàn)域?qū)ο蟆?

圖1示出的圖案的邏輯的概述,包括一些使用事件流,例如,創(chuàng)建的物化視圖,與外部應(yīng)用程序和系統(tǒng)整合事件,并重放事件來(lái)創(chuàng)建特定實(shí)體的當(dāng)前狀態(tài)的突起的選項(xiàng)。

http://wiki.jikexueyuan.com/project/cloud-design-patterns/images/em.png" alt="" />

圖1 - 的情況下獲取模式的概述和示例

事件獲取模式提供了許多優(yōu)點(diǎn),包括如下:

  • 活動(dòng)是不可變的,因此可以使用僅追加操作來(lái)保存。用戶界面,工作流或過(guò)程發(fā)起產(chǎn)生該事件可以繼續(xù),并且處理這些事件可以在后臺(tái)運(yùn)行的任務(wù)的操作。此,結(jié)合的事實(shí),有記錄的執(zhí)行過(guò)程中沒(méi)有爭(zhēng)用,可以極大地提高性能和可擴(kuò)展性的應(yīng)用,尤其是對(duì)于表示層或用戶界面。
  • 活動(dòng)是描述所發(fā)生的一些動(dòng)作,再加上描述的事件所代表的行動(dòng)所需的任何相關(guān)數(shù)據(jù)的簡(jiǎn)單對(duì)象。事件不直接更新數(shù)據(jù)存儲(chǔ);它們被簡(jiǎn)單地記錄用于處理在適當(dāng)?shù)臅r(shí)間。這些因素可以簡(jiǎn)化實(shí)施和管理。
  • 活動(dòng)通常意味著一個(gè)領(lǐng)域的專(zhuān)家,而對(duì)象關(guān)系的阻抗失配的復(fù)雜性可能意味著一個(gè)數(shù)據(jù)庫(kù)表可能無(wú)法清楚地了解該領(lǐng)域的專(zhuān)家。表是表示該系統(tǒng)中,未發(fā)生的事件的當(dāng)前狀態(tài),人工構(gòu)建體。
  • 事件的采購(gòu)可以幫助防止引起沖突,因?yàn)樗苊饬艘笾苯痈略跀?shù)據(jù)存儲(chǔ)對(duì)象的并發(fā)更新。然而,領(lǐng)域模型仍然必須用來(lái)保護(hù)自己免受可能導(dǎo)致不一致的狀態(tài)的請(qǐng)求。
  • 事件的僅追加存儲(chǔ)提供了可用于監(jiān)測(cè)對(duì)一個(gè)數(shù)據(jù)存儲(chǔ)所采取的行動(dòng)的審核跟蹤,??再生的當(dāng)前狀態(tài)作為通過(guò)重播事件隨時(shí)物化視圖或預(yù)測(cè),并協(xié)助測(cè)試和調(diào)試系統(tǒng)。此外,該規(guī)定使用補(bǔ)償事件取消變化提供了被逆轉(zhuǎn)的變化,這不會(huì)是如果模型簡(jiǎn)單地存儲(chǔ)在當(dāng)前狀態(tài)的情況下的歷史記錄。事件列表中,也可以用于分析應(yīng)用程序的性能,并檢測(cè)用戶行為趨勢(shì),或獲得其它有用的商業(yè)信息。
  • 從響應(yīng)進(jìn)行操作的事件存儲(chǔ)提出的每個(gè)事件的任何任務(wù)事件的解耦提供了靈活性和可擴(kuò)展性。例如,用于處理由所述事件存儲(chǔ)引發(fā)的事件的任務(wù)都知道只有事件的性質(zhì)和它包含的數(shù)據(jù)。時(shí)所執(zhí)行的任務(wù)的方式是從觸發(fā)事件的動(dòng)作去耦。此外,多個(gè)任務(wù)可以處理每個(gè)事件。這可能使得與其他服務(wù)和系統(tǒng),只需要監(jiān)聽(tīng)的事件存儲(chǔ)提出了新的事件,易于集成。然而,該事件采購(gòu)事件往往是非常低的水平,并且可能有必要以產(chǎn)生特異性整合事件來(lái)代替。

注意: 事件來(lái)源通常結(jié)合 CQRS 模式通過(guò)執(zhí)行數(shù)據(jù)管理任務(wù)響應(yīng)于所述事件,并通過(guò)物化從所存儲(chǔ)的事件的意見(jiàn)。

問(wèn)題和注意事項(xiàng)

在決定如何實(shí)現(xiàn)這個(gè)模式時(shí),請(qǐng)考慮以下幾點(diǎn):

  • 創(chuàng)建物化視圖或重放事件產(chǎn)生的數(shù)據(jù)的預(yù)測(cè)時(shí),系統(tǒng)只會(huì)是最終一致。有一個(gè)應(yīng)用程序添加事件,事件存儲(chǔ)作為處理一個(gè)請(qǐng)求的結(jié)果之間有一些延遲,被公布事件,而消費(fèi)者對(duì)事件的處理它們。在此期間,描述該進(jìn)一步修改實(shí)體的新的事件可能已到達(dá)的情況下存儲(chǔ)。

注意: 請(qǐng)參閱數(shù)據(jù)一致性底漆有關(guān)最終一致性的信息。

  • 事件存儲(chǔ)是信息不可變?cè)?,因此事件?shù)據(jù)不應(yīng)該被更新。要以撤銷(xiāo)變更更新一個(gè)實(shí)體的唯一辦法是補(bǔ)償?shù)氖录砑拥绞录鎯?chǔ),就像你會(huì)用負(fù)數(shù)交易的會(huì)計(jì)核算。如果持久化事件的格式(而不是數(shù)據(jù))需要改變,或者在遷移過(guò)程中,可能難以對(duì)現(xiàn)有的事件結(jié)合在商店的新版本。可能有必要通過(guò)所有更改的事件來(lái)循環(huán)以使它們符合新格式,或添加使用該新格式的新事件??紤]使用上的每個(gè)版本的事件模式的版本標(biāo)記,以保持舊的和新的事件格式。
  • 多線程應(yīng)用程序和應(yīng)用程序的多個(gè)實(shí)例可以被存儲(chǔ)在事件存儲(chǔ)事件。在事件存儲(chǔ)事件的一致性是非常重要的,是影響到特定實(shí)體(的順序改變?yōu)橐粋€(gè)實(shí)體發(fā)生影響其當(dāng)前狀態(tài))的事件的順序。添加時(shí)間戳到每一個(gè)事件是一個(gè)選項(xiàng),可以幫助避免出現(xiàn)問(wèn)題。另一種常見(jiàn)的做法是將注釋每一個(gè)事件所導(dǎo)致使用增量標(biāo)識(shí)符的請(qǐng)求。如果兩個(gè)動(dòng)作試圖為同一實(shí)體的同時(shí)添加的事件,該事件存儲(chǔ)可以拒絕匹配現(xiàn)有實(shí)體標(biāo)識(shí)符和事件標(biāo)識(shí)符事件。
  • 有沒(méi)有標(biāo)準(zhǔn)的方法,還是準(zhǔn)備建機(jī)制,如 SQL 查詢(xún),讀取事件來(lái)獲取信息。可以提取的唯一數(shù)據(jù)是使用事件標(biāo)識(shí)符作為條件的事件流。事件ID通常映射到單個(gè)實(shí)體。一個(gè)實(shí)體的當(dāng)前狀態(tài),可以?xún)H通過(guò)重放所有涉及到它針對(duì)該實(shí)體的原始狀態(tài)的事件的確定。
  • 每個(gè)事件流的長(zhǎng)度可以有上管理并更新該系統(tǒng)的后果。如果流很大,可以考慮創(chuàng)建以特定的間隔的快照,如活動(dòng)指定數(shù)量??梢詮脑摽煺?,通過(guò)重放該時(shí)間點(diǎn)之后發(fā)生的任何事件中得到的實(shí)體的當(dāng)前狀態(tài)。

注意: 有關(guān)創(chuàng)建數(shù)據(jù)快照的更多信息,請(qǐng)參見(jiàn)Martin Fowler的企業(yè)應(yīng)用架構(gòu)的網(wǎng)站和主從快照復(fù)制MSDN上的快照。

  • 盡管采購(gòu)活動(dòng)減少?zèng)_突的更新數(shù)據(jù)的機(jī)會(huì),應(yīng)用程序必須仍然能夠應(yīng)付可能出現(xiàn)的通過(guò)最終一致性和缺乏交易的不一致。例如,一個(gè)事件,指示庫(kù)存的庫(kù)存的減少可能在數(shù)據(jù)存儲(chǔ)到達(dá),而對(duì)于該產(chǎn)品的訂單被放置,從而導(dǎo)致需求調(diào)和這兩種業(yè)務(wù);可能是建議客戶或創(chuàng)建后順序。
  • 事件發(fā)布可能是“至少一次”等消費(fèi)者的事件,必須冪等。它們不能重新在一個(gè)事件描述,如果該事件被處理多于一次的更新。例如,如果一消費(fèi)者的多個(gè)實(shí)例保持一些實(shí)體的一個(gè)屬性的集合,如訂單放置的總數(shù)中,只有一個(gè)必須在當(dāng)一個(gè)“順序放置”事件發(fā)生時(shí),遞增該聚合成功。雖然這不是事件來(lái)源的固有特性,它是通常的實(shí)現(xiàn)決策。

當(dāng)使用這個(gè)模式

這種模式非常適合以下情況:

  • 當(dāng)你想捕捉“意圖”,“目的”或“理”中的數(shù)據(jù)。例如,如動(dòng)家,已關(guān)閉帳戶,或已故變?yōu)橐粋€(gè)客戶實(shí)體可被捕捉為一系列特定的事件類(lèi)型。
  • 當(dāng)它是至關(guān)重要的,盡量減少或完全避免更新沖突的發(fā)生數(shù)據(jù)。
  • 當(dāng)你想記錄發(fā)生的事件,并能夠重放它們來(lái)恢復(fù)系統(tǒng)的狀態(tài);用它們來(lái)回滾更改的系統(tǒng);或者簡(jiǎn)單地作為一個(gè)歷史和審計(jì)日志。例如,當(dāng)一個(gè)任務(wù)涉及多個(gè)步驟,您可能需要執(zhí)行恢復(fù)更新操作,然后重放一些步驟,使數(shù)據(jù)恢復(fù)到一致?tīng)顟B(tài)。
  • 當(dāng)使用事件是應(yīng)用程序的動(dòng)作的自然特征,并且需要很少的額外的開(kāi)發(fā)或?qū)崿F(xiàn)工作。
  • 當(dāng)您需要輸入分離或應(yīng)用這些行動(dòng)所需的任務(wù)更新數(shù)據(jù)的過(guò)程。這可能是為了提高用戶界面的性能,或分發(fā)事件到其它聽(tīng)眾如其他應(yīng)用程序或服務(wù),必須采取某些行動(dòng)的事件發(fā)生時(shí)。一個(gè)例子是有費(fèi)用提交網(wǎng)站整合了工資制度,使響應(yīng)的費(fèi)用提交網(wǎng)站做數(shù)據(jù)的更新提出的事件存儲(chǔ)事件由兩個(gè)網(wǎng)站和工資系統(tǒng)消耗。
  • 當(dāng)您想要的靈活性,能夠改變實(shí)體化模型和實(shí)體數(shù)據(jù)的格式,如果需求發(fā)生變化,或者,當(dāng)結(jié)合使用 CQRS,你需要適應(yīng)的讀模式或公開(kāi)數(shù)據(jù)的意見(jiàn)。
  • 與 CQRS 一起使用時(shí),和最終一致性是可以接受的,而讀出的模型被更新,或者,在從事件流中再水化的實(shí)體和數(shù)據(jù)發(fā)生的性能的影響是可以接受的。

這種模式可能不適合于下列情況:

  • 小型或簡(jiǎn)單的領(lǐng)域,很少或沒(méi)有業(yè)務(wù)邏輯,或者非域系統(tǒng),自然與傳統(tǒng)的 CRUD 的數(shù)據(jù)管理機(jī)制,運(yùn)作良好的系統(tǒng)。
  • 哪里的一致性和實(shí)時(shí)更新數(shù)據(jù)的意見(jiàn)是必需的系統(tǒng)。
  • 不要求系統(tǒng)中的審計(jì)跟蹤,歷史,功能,回滾和回放操作。
  • 系統(tǒng)中只有非常低的沖突更新到基礎(chǔ)數(shù)據(jù)的發(fā)生。例如,主要為添加數(shù)據(jù)而不是更新它的系統(tǒng)。

例子

的會(huì)議管理系統(tǒng)需要跟蹤會(huì)議完成了預(yù)定的數(shù)量,以便它可以檢查是否有座位仍然可用時(shí),一個(gè)潛在的與會(huì)者試圖做一個(gè)新的預(yù)訂。該系統(tǒng)可以存儲(chǔ)預(yù)定的總數(shù)為在至少兩個(gè)方面的會(huì)議:

  • 該系統(tǒng)可以存儲(chǔ)關(guān)于預(yù)約的總數(shù)作為數(shù)據(jù)庫(kù)中的該擱置預(yù)約信息的獨(dú)立的實(shí)體的信息。作為預(yù)訂制成或取消訂單,則系統(tǒng)可以增加或減少該數(shù)量適當(dāng)。這種方法在理論上是簡(jiǎn)單的,但可引起可擴(kuò)展性問(wèn)題,如果有大量的與會(huì)者試圖進(jìn)行預(yù)訂時(shí)的短時(shí)間內(nèi)座位。例如,在最后一天或預(yù)約期間閉合,以便之前。
  • 該系統(tǒng)可以存儲(chǔ)大約預(yù)訂和取消如在事件存儲(chǔ)舉辦的活動(dòng)信息。然后,它可以計(jì)算出可用通過(guò)重播這些事件的席位數(shù)。這種方法可以更加擴(kuò)展性由于事件的不變性。該系統(tǒng)只需要能夠從事件存儲(chǔ)讀取數(shù)據(jù),或?qū)?shù)據(jù)追加到該事件存儲(chǔ)。關(guān)于預(yù)訂和取消事件信息不會(huì)被修改。

圖2顯示了如何將會(huì)議管理系統(tǒng)的座位子系統(tǒng)可能通過(guò)采購(gòu)活動(dòng)來(lái)實(shí)現(xiàn)。

http://wiki.jikexueyuan.com/project/cloud-design-patterns/images/em2.png" alt="" />

圖2 - 使用事件來(lái)源獲取關(guān)于座位預(yù)訂信息,在會(huì)議管理系統(tǒng)

行動(dòng)預(yù)留兩個(gè)座位的順序如下:

1.用戶界面發(fā)出命令,以預(yù)留座位有兩個(gè)人參加。該命令是由一個(gè)單獨(dú)的命令處理程序(一塊邏輯的是從用戶界面分離,并負(fù)責(zé)張貼的命令處理請(qǐng)求)處理。 包含所有預(yù)訂的會(huì)議信息

2.一種聚集通過(guò)查詢(xún)描述預(yù)訂和取消的事件構(gòu)成。該集合體被稱(chēng)為 SeatAvailability,并且被包含在暴露在聚合查詢(xún)和修改的數(shù)據(jù)的方法的域模型。

注意: 一些優(yōu)化利用快照(這樣就不需要查詢(xún)和重放事件的完整列表,以獲得聚集的當(dāng)前狀態(tài)),并維持聚合的在存儲(chǔ)器中的高速緩存副本來(lái)考慮。

3,命令處理程序調(diào)用的域模型曝光,使保留的方法。

4.SeatAvailability 骨料記錄包含的席位被保留數(shù)量的事件。聚合應(yīng)用事件接下來(lái)的時(shí)間,所有的預(yù)訂將被用來(lái)計(jì)算的座位有多少仍然存在。

5.系統(tǒng)追加了新的事件在事件存儲(chǔ)的事件列表。

如果一個(gè)用戶希望取消一個(gè)座位,該系統(tǒng)遵循不同的是,命令處理程序發(fā)出,其生成一個(gè)座位取消事件,并將其追加到事件存儲(chǔ)區(qū)中的命令類(lèi)似的過(guò)程

以及可擴(kuò)展性提供更大的空間,使用事件店內(nèi)還提供了一個(gè)完整的歷史,或?qū)徲?jì)追蹤,預(yù)訂和取消了會(huì)議。記錄在事件存儲(chǔ)在事件真相的權(quán)威和唯一來(lái)源。沒(méi)有必要持續(xù)聚集體中的任何其他方法,因?yàn)樵撓到y(tǒng)可以很容易地重放這些事件和恢復(fù)狀態(tài),以任意的時(shí)間點(diǎn)。