微服務(wù)業(yè)務(wù)開發(fā)三個(gè)難題-拆分尸疆、事務(wù)椿猎、查詢(下)

上集我們闡述了使用微服務(wù)體系架構(gòu)的關(guān)鍵障礙是領(lǐng)域模型,事務(wù)和查詢寿弱,這三個(gè)障礙似乎和功能拆分具有天然的對(duì)抗犯眠。只要功能拆分了,就涉及這三個(gè)難題症革。

然后我們向你展示了一種解決方案就是將每個(gè)服務(wù)的業(yè)務(wù)邏輯實(shí)現(xiàn)為一組DDD聚合筐咧。然后每個(gè)事務(wù)只能更新或創(chuàng)建一個(gè)單獨(dú)的聚合。然后通過事件來維護(hù)聚合(和服務(wù))之間的數(shù)據(jù)一致性噪矛。

在本集中量蕊,我們將會(huì)向你介紹使用事件的時(shí)候遇到了一個(gè)新的問題,就是怎么樣通過原子方式更新聚合和發(fā)布事件艇挨。然后會(huì)展示如何使用事件源來解決這個(gè)問題残炮,事件源是一種以事件為中心的業(yè)務(wù)邏輯設(shè)計(jì)和持久化的方法。之后缩滨,我們會(huì)闡述微服務(wù)架構(gòu)下的查詢困難的問題势就。然后向你介紹一種稱為命令查詢責(zé)任分離(CQRS)的方法來實(shí)現(xiàn)可擴(kuò)展和高性能的查詢。

可靠地更新狀態(tài)和發(fā)布事件

從表面上看脉漏,使用事件來保持聚合之間的一致性似乎很簡單苞冯。

當(dāng)一個(gè)服務(wù)創(chuàng)建或更新數(shù)據(jù)庫的一個(gè)聚合時(shí),它只是簡單地發(fā)布一個(gè)事件侧巨。

但是舅锄,這只是表象,其實(shí)還有一個(gè)核心問題就是:更新數(shù)據(jù)庫和發(fā)布事件必須是原子的司忱。否則皇忿,就會(huì)出現(xiàn)類似這樣的情況:如果服務(wù)在更新數(shù)據(jù)庫之后但在發(fā)布事件之前崩潰,則系統(tǒng)就出現(xiàn)了不一致的問題坦仍。

傳統(tǒng)的解決方案是一般都是使用分布式事務(wù)來搞鳍烁,一個(gè)涉及數(shù)據(jù)庫和消息broker的分布式事務(wù)。但是桨踪,由于上一集所述的原因老翘,2PC不是一個(gè)可行的選擇。

其實(shí)除了2PC ,還有幾種解決這個(gè)問題的方法铺峭。

一種解決方案就是墓怀,應(yīng)用程序可以通過向類似Kafka這樣的消息中間件的broker發(fā)布一個(gè)事件來執(zhí)行更新。然后一個(gè)消息consumer訂閱這個(gè)事件卫键,通過消費(fèi)該事件然后最終更新數(shù)據(jù)庫傀履。這種方法可以確保數(shù)據(jù)庫被更新并且事件被發(fā)布。

但是缺點(diǎn)就是這種一致性模型過于復(fù)雜莉炉,至少有點(diǎn)復(fù)雜钓账。而且應(yīng)用程序不能夠立即讀取到自己剛剛的寫入。

圖1 - 通過發(fā)布事件到消息broker來更新數(shù)據(jù)庫

另一種做法就是絮宁,如圖2所示梆暮,就是應(yīng)用程序追加事務(wù)日志到數(shù)據(jù)庫(a.k.a.commit log),將每個(gè)記錄的更改轉(zhuǎn)換為事件绍昂,然后把事件發(fā)布到消息broker啦粹。這種做法的一個(gè)重要好處就是應(yīng)用程序本身不需要任何的改變。

然而窘游,一個(gè)缺點(diǎn)是唠椭,這種做法是一種底層(low-level)的事件,而不是上層業(yè)務(wù)事件忍饰√吧可能難以將上層業(yè)務(wù)事件(由于數(shù)據(jù)庫更新的原因)從底層更改逆轉(zhuǎn)到表中的行。

原文:it can be difficult toreverse engineer the high-level business event - the reason for the databaseupdate - from the low-level changes to the rows in the tables.

圖****2 - ****追加數(shù)據(jù)庫事務(wù)日志

第三種解決方案就是艾蓝,圖3所示的這種力崇,使用數(shù)據(jù)庫表來作為一種臨時(shí)性的message queue。當(dāng)一個(gè)服務(wù)更新一個(gè)聚合饶深,它會(huì)insert一個(gè)事件到EVENTS表餐曹,作為本地ACID事務(wù)的一部分逛拱。然后一個(gè)單獨(dú)的進(jìn)程輪詢EVENTS表并將事件發(fā)布到消息broker敌厘。

這種做法的好處就是service能夠發(fā)布high-level的業(yè)務(wù)事件。

缺點(diǎn)是這種做法容易出錯(cuò)朽合,有這種潛在的可能俱两,因?yàn)槭录l(fā)布代碼必須與業(yè)務(wù)邏輯同步。

圖****3 - ****使用數(shù)據(jù)庫表作為****message queue

上面三種做法都有比較典型的缺點(diǎn)曹步。

發(fā)布一個(gè)事件到****message broker****并稍后更新的做法總是不能提供一種read-your-writes的一致性宪彩,也就是只能保證最終一致。

追加事務(wù)日志提供了一致的讀取讲婚,但卻不能發(fā)布高級(jí)業(yè)務(wù)事件尿孔。

使用數(shù)據(jù)庫表作為message queue提供了一致的讀取并且可以發(fā)布high-level業(yè)務(wù)事件,但

卻對(duì)開發(fā)人員有依賴,就是開發(fā)人員得記得在狀態(tài)發(fā)生改變的時(shí)候加上發(fā)布事件的邏輯活合。

幸運(yùn)的是雏婶,我們還有另外一種解決方案,那就是event sourcing白指,事件源留晚。它是一種針對(duì)持久化和業(yè)務(wù)邏輯的一種以事件為中心方法,稱為事件源告嘲。這里解釋的不夠清楚错维,稍后慢慢展開。

使用事件源來開發(fā)微服務(wù)

事件源(Event sourcing)是一種以事件為中心的持久化方法橄唬。這不是一個(gè)新的概念赋焕。

我第一次了解到這個(gè)概念是在大概五年多以前,之后對(duì)這個(gè)新生事物一直充滿了好奇仰楚,直到我開始開發(fā)微服務(wù)宏邮。接下來,你將會(huì)看到通過事件源來實(shí)現(xiàn)事件驅(qū)動(dòng)的微服務(wù)架構(gòu)是多么不錯(cuò)的一種方法缸血。

一個(gè)service通過event sourcing使用一系列的事件來持久化每個(gè)聚合蜜氨。

當(dāng)創(chuàng)建或更新一個(gè)聚合的時(shí)候,這個(gè)service會(huì)在數(shù)據(jù)庫里保存一個(gè)或多個(gè)事件捎泻,這種數(shù)據(jù)庫里存儲(chǔ)event的方式可以叫做是event store飒炎,以下我們就叫“事件數(shù)據(jù)庫”。

它通過加載這些事件并replay這些事件笆豁,從而實(shí)現(xiàn)更新聚合的當(dāng)前狀態(tài)郎汪。

在函數(shù)式編程里,一個(gè)service通過執(zhí)行一個(gè)函數(shù)式的fold或reduce來重構(gòu)聚合闯狱,而不是事件煞赢。

由于事件就是狀態(tài),所以你就不會(huì)再有原子地更新狀態(tài)和發(fā)布事件的問題了哄孤。

例如照筑,比如訂單服務(wù)(Order Service)。不是將每個(gè)訂單作為一行存儲(chǔ)在ORDERS表中瘦陈,而是將每個(gè)訂單聚合作為一系列的事件凝危,比如訂單已創(chuàng)建,訂單已批準(zhǔn)晨逝,訂單已發(fā)貨等持久化到EVENTS表中蛾默。圖4顯示了這些事件如何存儲(chǔ)在基于SQL的事件數(shù)據(jù)庫(event store)中。

圖****4 - ****使用事件源來持久化一個(gè)訂單

每列的意思:

  • entity_typeentity_id –唯一標(biāo)識(shí)一個(gè)聚合

  • event_id – 事件ID捉貌,唯一標(biāo)識(shí)

  • event_type – 事件類型

  • event_data -事件屬性的序列化JSON表示

一些事件包含大量數(shù)據(jù)支鸡。例如冬念,訂單創(chuàng)建(Order Created)事件包含完整訂單,包括其訂單項(xiàng)牧挣,付款信息和交貨信息刘急。其他事件,如訂單出貨(Order Shipped)事件浸踩,包含很少或沒有數(shù)據(jù)叔汁,只是表示狀態(tài)轉(zhuǎn)換。

事件源(****Event Sourcing****)和發(fā)布事件

嚴(yán)格的講检碗,事件源只是簡單的將聚合們作為事件進(jìn)行了持久化据块。更直接的說,就是使用事件源來作為一種可靠的事件發(fā)布機(jī)制折剃。保存一個(gè)事件是一個(gè)固有的原子操作另假,它可以確保事件數(shù)據(jù)庫(event store)把事件傳遞給感興趣的服務(wù)。

例如怕犁,如果事件被存儲(chǔ)在上面所示的EVENTS表中边篮,訂閱者可以簡單地輪詢表以查找新事件。更復(fù)雜的事件數(shù)據(jù)庫(event store)將使用另一種做法奏甫,這種做法具有更高性能和可擴(kuò)展性戈轿。例如,Eventuate Local使用追加事務(wù)日志的方式阵子。它從MySQL replication流中讀取插入到EVENTS表中的事件思杯,并將它們發(fā)布到Apache Kafka。

至于Eventuate Local是個(gè)什么鬼挠进?你可以去github 搜搜色乾。下面放一張圖:

使用****Snapshot****改善性能

訂單(Order)聚合具有相對(duì)較少的狀態(tài)轉(zhuǎn)換,因此它只有少量的事件领突。

所以暖璧,針對(duì)這些事件查詢事件數(shù)據(jù)庫(event store)并重構(gòu)Order聚合,效率是不錯(cuò)的君旦。然而澎办,一些聚合有很多的事件。例如于宙,客戶(Customer)聚合可能有大量的預(yù)留信用(Credit Reserved)事件浮驳。隨著時(shí)間的推移悍汛,加載和消費(fèi)(fold)這些事件的效率會(huì)越來越低捞魁。

一個(gè)常見的解決方案是定期保存聚合狀態(tài)的快照(snapshot)。應(yīng)用程序通過加載最近的快照然后從快照創(chuàng)建之后發(fā)生的那些事件開始來恢復(fù)聚合的狀態(tài)离咐。

在函數(shù)式下谱俭,快照就是折疊(fold)的初始值奉件。(原文:In functional terms, the snapshot is the initial value of thefold. )如果聚合是一個(gè)簡單,容易序列化的結(jié)構(gòu)昆著,則快照可以簡單地是JSON序列化格式县貌。更復(fù)雜的聚合可以使用Memento模式(Mementopattern)進(jìn)行快照。至于這種設(shè)計(jì)模式具體是什么鬼凑懂,你可以自己查閱煤痕。

在線商店示例中的客戶(Customer)聚合具有非常簡單的結(jié)構(gòu):客戶的信息,他們的信用額度(credit limit)和他們的信用預(yù)留(credit reservations)接谨。

客戶(Customer)的快照只是其狀態(tài)的JSON序列化摆碉。圖5展現(xiàn)了如何從與事件#103的客戶(Customer)的狀態(tài)相對(duì)應(yīng)的快照中重新創(chuàng)建一個(gè)客戶(Customer)∨Ш溃客戶服務(wù)(Customer Service)只需要加載快照和加載事件#103后發(fā)生的事件巷帝。

圖****5 – ****使用快照來優(yōu)化性能

客戶服務(wù)(Customer Service)通過反序列化快照的JSON后加載并消費(fèi)#104到#106的事件來重新創(chuàng)建那個(gè)客戶(Customer)。

事件源實(shí)現(xiàn)

事件數(shù)據(jù)庫(event store)是數(shù)據(jù)庫和消息borker的混合體扫夜。它是一個(gè)數(shù)據(jù)庫楞泼,因?yàn)樗幸粋€(gè)API,用于通過主鍵插入和檢索聚合的事件笤闯。事件數(shù)據(jù)庫(event store)也是消息broker堕阔,因?yàn)樗哂杏糜谟嗛喪录腁PI。

有一些不同的方法來實(shí)現(xiàn)事件數(shù)據(jù)庫(event store)颗味。

一個(gè)做法是編寫自己的事件源框架印蔬。例如,您可以在RDBMS中持久化事件脱衙。一種簡單的侥猬,但性能略低的方式來發(fā)布事件,然后訂閱者輪詢事件的EVENTS表捐韩。

另一個(gè)做法是使用專用的事件數(shù)據(jù)庫(event store)退唠,它通常能夠提供更豐富的功能以及更好的性能和可擴(kuò)展性』缧玻“事件源”的開發(fā)者之一Greg Young有一個(gè)基于.NET的開源事件數(shù)據(jù)庫瞧预,稱為Event Store。 Lightbend仅政,這個(gè)公司以前叫Typesafe垢油,有一個(gè)叫Lagom的微服務(wù)框架,是基于事件源的圆丹。這里推薦一個(gè)我自己的創(chuàng)業(yè)項(xiàng)目滩愁,Eventuate,一個(gè)用于微服務(wù)的事件源框架辫封,你可以把它作為一個(gè)云服務(wù)硝枉,你也可以把它認(rèn)為是一個(gè)基于Kafka 或RDBMS的開源項(xiàng)目廉丽。

事件源的好處與缺點(diǎn)

事件源有好處也有缺點(diǎn)。

事件源的一個(gè)主要優(yōu)點(diǎn)是它可以在聚合的狀態(tài)發(fā)生變化時(shí)可靠地發(fā)布事件妻味。它為事件驅(qū)動(dòng)的微服務(wù)架構(gòu)打下了良好的基礎(chǔ)正压。而且,由于每個(gè)事件都可以記錄進(jìn)行更改的用戶的身份责球,因此事件源還提供了一個(gè)準(zhǔn)確的審核日志焦履。事件流可用于各種其他目的,包括向用戶發(fā)送通知以及應(yīng)用集成等等雏逾。

事件源的另一個(gè)好處是它存儲(chǔ)每個(gè)聚合的整個(gè)歷史裁良。你可以輕松實(shí)現(xiàn)檢索聚合的過去狀態(tài)的時(shí)態(tài)查詢。要確定在給定時(shí)間點(diǎn)的聚合的狀態(tài)校套,您只需消費(fèi)(fold)直到該點(diǎn)為止發(fā)生的事件价脾。例如,可以直接計(jì)算過去某個(gè)時(shí)間點(diǎn)客戶的可用信用額笛匙。

事件源也避免了O / R阻抗失衡的問題侨把。這是因?yàn)樗志没耸录皇蔷酆稀J录ǔ>哂泻唵蚊盟铮菀仔蛄谢慕Y(jié)構(gòu)秋柄。服務(wù)(service)可以通過序列化其狀態(tài)的記錄來對(duì)復(fù)雜聚合進(jìn)行快照。 Memento模式在聚合和它的序列化表示之間增加了一個(gè)中間層蠢正。

有關(guān)O/R impedance mismatch:

對(duì)象關(guān)系阻抗失衡(object-relational impedance mismatch )是當(dāng)關(guān)系數(shù)據(jù)庫管理系統(tǒng)(RDBMS)由以面向?qū)ο蟮木幊陶Z言或風(fēng)格編寫的應(yīng)用程序(或多個(gè)應(yīng)用程序)服務(wù)時(shí)經(jīng)常遇到的一組概念和技術(shù)困難骇笔,特別是因?yàn)閷?duì)象或類定義必須映射到關(guān)系模式定義的數(shù)據(jù)庫表。

事件源當(dāng)然不是完美的嚣崭,它也有一些缺點(diǎn)笨触。它是一個(gè)完全不一樣的和而且你可能并不熟悉的編程模型,所以要花一些時(shí)間去學(xué)習(xí)雹舀。為了使現(xiàn)有應(yīng)用程序使用事件源芦劣,你必須要重寫業(yè)務(wù)邏輯。幸運(yùn)的是说榆,這是一個(gè)相當(dāng)機(jī)械的轉(zhuǎn)換虚吟,你可以在將應(yīng)用程序遷移到微服務(wù)的時(shí)候做這件事情。

事件源的另一個(gè)缺點(diǎn)是消息broker通常保證至少一次(at-least once)傳遞签财。非冪等的事件處理handler必須檢測并丟棄那些重復(fù)的事件串慰。事件源框架可以通過為每個(gè)事件分配單調(diào)遞增的id來解決這個(gè)問題。事件處理handler然后可以通過對(duì)最大事件ID跟蹤來檢測重復(fù)事件唱蒸。

事件源的另一個(gè)局限就是事件(和快照0铞辍)的schema將隨時(shí)間發(fā)展。 由于事件永久存儲(chǔ)油宜,當(dāng)服務(wù)重建聚合時(shí)掂碱,服務(wù)可能需要折疊與多個(gè)schema版本對(duì)應(yīng)的事件怜姿。 簡化服務(wù)的一種方法是慎冤,當(dāng)事件源框架從事件數(shù)據(jù)庫(event store)加載它們時(shí)疼燥,將所有事件轉(zhuǎn)換為最新版本的模式。因此蚁堤,服務(wù)只需消費(fèi)(fold)最新版本的事件醉者。

事件源的另一個(gè)缺點(diǎn)是查詢事件數(shù)據(jù)庫(event store)可能比較困難。讓我們想象一下披诗,例如撬即,您需要找到信用額度較低的客戶。你不能簡單地寫SELECT * FROM CUSTOMERWHERE CREDIT_LIMIT <呈队? AND c.CREATION_DATE>剥槐?。因?yàn)楦揪蜎]有信用額度(CREDIT_LIMIT)這樣的列宪摧。相反粒竖,你不得不使用嵌套SELECT的更復(fù)雜而且還可能無效的查詢筷登,通過處理和消費(fèi)(fold)事件來計(jì)算信用額度疾棵。更糟糕的是,基于NoSQL的事件數(shù)據(jù)庫(event store)通常只支持基于主鍵的查找刽锤。因此沿彭,必須使用“命令查詢責(zé)任分離“(CQRS)的方法實(shí)施查詢朽砰。CQRS 的全稱:Command Query Responsibility Segregation。

我們接下來的內(nèi)容就是介紹CQRS喉刘。

使用****CQRS****實(shí)現(xiàn)查詢

事件源是在微服務(wù)體系結(jié)構(gòu)中實(shí)現(xiàn)高效查詢的主要障礙瞧柔。這還不是唯一的問題,還有比如你使用SQL去查找一些高價(jià)值訂單的新客戶睦裳。

<pre style="font-family: "Courier New"; margin: 0px; padding: 0px; font-size: 9.8pt; width: 823.672px; overflow: auto; background: rgb(43, 43, 43); max-width: 100%; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; color: rgb(169, 183, 198);">SELECT *
FROM CUSTOMER c, ORDER o
WHERE
c.id = o.ID
AND o.ORDER_TOTAL > 100000
AND o.STATE = 'SHIPPED'
AND c.CREATION_DATE > ?</pre>

在微服務(wù)架構(gòu)中非剃,你不能join CUSTOMER和ORDER這兩張表。每個(gè)表由不同的服務(wù)所擁有推沸,并且只能通過該服務(wù)的API訪問备绽。你不能編寫連接多個(gè)服務(wù)所擁有的表的傳統(tǒng)查詢。事件源使事情變得更糟鬓催,阻礙你編寫簡單肺素,直接的查詢。讓我們來看看在微服務(wù)架構(gòu)中是如何實(shí)現(xiàn)類似查詢的宇驾。

如何使用****CQRS

實(shí)現(xiàn)查詢的好方法是使用稱為命令查詢責(zé)任分離(CQRS)的體系結(jié)構(gòu)模式: Command Query Responsibility Segregation倍靡。如名稱所示,CQRS將應(yīng)用程序分為兩部分课舍。第一部分是命令側(cè)(command-side)塌西,其處理命令(例如他挎,HTTP POST,PUT和DELETE)以創(chuàng)建捡需,更新和刪除聚合办桨。前提是這些聚合是使用事件源實(shí)現(xiàn)的。應(yīng)用程序的第二部分是查詢側(cè)(query-side)站辉,其通過查詢聚合的一個(gè)或多個(gè)物化視圖(materialized views)來處理查詢(例如HTTP GET)呢撞。查詢側(cè)通過訂閱由命令側(cè)發(fā)布的事件來保持視圖(view)與聚合(aggregate)同步。

查詢側(cè)(query-side)視圖可以使用任何類型的能滿足需求的數(shù)據(jù)庫來實(shí)現(xiàn)饰剥。根據(jù)需求殊霞,應(yīng)用程序的查詢端可能使用一個(gè)或多個(gè)以下數(shù)據(jù)庫:

表****1. ****查詢側(cè)視圖數(shù)據(jù)庫選擇

在很多場合,CQRS是一個(gè)以事件為基礎(chǔ)(event-based)的綜合體汰蓉,比如使用RDBMS作為記錄系統(tǒng)再使用比如Elasticsearch來處理文本查詢绷蹲。CQRS的查詢側(cè)可以使用其它類型的數(shù)據(jù)庫,支持多種類型的數(shù)據(jù)庫顾孽,不僅僅是文本搜索引擎祝钢。而且,它通過訂閱事件準(zhǔn)實(shí)時(shí)地去更新查詢側(cè)的視圖岩齿。

圖6顯示了應(yīng)用于在線商店示例的CQRS模式太颤。客戶服務(wù)(Customer Service)和訂單服務(wù)(Order Service)是命令端服務(wù)盹沈。它們提供用于創(chuàng)建和更新客戶和訂單的API龄章。客戶視圖服務(wù)(Customer View Service)是查詢側(cè)服務(wù)乞封。它提供了一個(gè)用于查詢客戶的API做裙。

圖****6 – ****在線商店中使用**** CQRS

客戶視圖服務(wù)(Customer View Service)訂閱命令端服務(wù)發(fā)布的客戶(Customer)和訂單(Order)事件。它更新那個(gè)用MongoDB實(shí)現(xiàn)的視圖存儲(chǔ)(view store)肃晚。該服務(wù)維護(hù)一個(gè)MongoDB文檔集合锚贱,每個(gè)客戶一個(gè)。每個(gè)文檔都具有客戶詳細(xì)信息的屬性关串。它還具有存儲(chǔ)客戶最近訂單的屬性拧廊。此集合支持各種查詢,包括上面說到的那些查詢晋修。

CQRS****的好處和缺點(diǎn)

CQRS既有優(yōu)點(diǎn)也有缺點(diǎn)吧碾。 CQRS的一個(gè)主要優(yōu)點(diǎn)是它可以在微服務(wù)架構(gòu)中實(shí)現(xiàn)查詢,特別是使用事件源的架構(gòu)墓卦。它使應(yīng)用程序有效地支持一組不同的查詢倦春。另一個(gè)好處就是把命令側(cè)和查詢側(cè)分離,達(dá)到了解耦的作用。

CQRS也有一些缺點(diǎn)睁本。一個(gè)缺點(diǎn)就是需要額外的工作來開發(fā)和維護(hù)這套系統(tǒng)尿庐。你需要開發(fā)和部署更新和查詢視圖的查詢端服務(wù)。還有就是你需要部署視圖數(shù)據(jù)庫(view store)呢堰。

CQRS的另一個(gè)缺點(diǎn)是處理命令側(cè)和查詢側(cè)視圖之間的“滯后”抄瑟。查詢層相比命令側(cè)存在一定的時(shí)延。更新聚合暮胧,然后立即查詢視圖的客戶端應(yīng)用程序可能會(huì)看到聚合的以前版本锐借。所以必須通過一些手法來避免暴露這些潛在的不一致性給用戶问麸。

總結(jié)

使用事件來維護(hù)服務(wù)之間的數(shù)據(jù)一致性時(shí)的主要挑戰(zhàn)是原子級(jí)地更新數(shù)據(jù)庫和發(fā)布事件往衷。傳統(tǒng)的解決方案是使用跨數(shù)據(jù)庫和消息broker的分布式事務(wù)。然而严卖,2PC不是現(xiàn)代應(yīng)用的可行技術(shù)席舍。更好的方法是使用事件源,這是一種以事件為中心的方法來處理業(yè)務(wù)邏輯設(shè)計(jì)和持久化哮笆。

微服務(wù)架構(gòu)中的另一個(gè)挑戰(zhàn)是查詢来颤。查詢通常需要join由多個(gè)服務(wù)擁有的數(shù)據(jù)。但是稠肘,join不能再使用了福铅,因?yàn)閿?shù)據(jù)對(duì)每個(gè)服務(wù)都是私有的。使用事件源還使得更加難以有效地實(shí)現(xiàn)查詢项阴,因?yàn)楫?dāng)前狀態(tài)沒有被顯式地存儲(chǔ)滑黔。解決方案是使用命令查詢責(zé)任分離(CQRS)并維護(hù)可以容易查詢的聚合的一個(gè)或多個(gè)物化視圖。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末环揽,一起剝皮案震驚了整個(gè)濱河市略荡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌歉胶,老刑警劉巖汛兜,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異通今,居然都是意外死亡粥谬,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門辫塌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來漏策,“玉大人,你說我怎么就攤上這事璃氢∮寸瑁” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長巢寡。 經(jīng)常有香客問我喉脖,道長,這世上最難降的妖魔是什么抑月? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任树叽,我火速辦了婚禮,結(jié)果婚禮上谦絮,老公的妹妹穿的比我還像新娘题诵。我一直安慰自己,他們只是感情好层皱,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布性锭。 她就那樣靜靜地躺著,像睡著了一般叫胖。 火紅的嫁衣襯著肌膚如雪草冈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天瓮增,我揣著相機(jī)與錄音怎棱,去河邊找鬼。 笑死绷跑,一個(gè)胖子當(dāng)著我的面吹牛拳恋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播砸捏,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼谬运,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了带膜?” 一聲冷哼從身側(cè)響起吩谦,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎膝藕,沒想到半個(gè)月后式廷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芭挽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年滑废,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袜爪。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蠕趁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出辛馆,到底是詐尸還是另有隱情俺陋,我是刑警寧澤豁延,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站腊状,受9級(jí)特大地震影響诱咏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缴挖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一袋狞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧映屋,春花似錦苟鸯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至乙濒,卻和暖如春陕赃,著一層夾襖步出監(jiān)牢的瞬間卵蛉,已是汗流浹背颁股。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留傻丝,地道東北人甘有。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像葡缰,于是被迫代替她去往敵國和親亏掀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容