微服務(wù)實踐(五):微服務(wù)的事件驅(qū)動數(shù)據(jù)管理

微服務(wù)實踐(五):微服務(wù)的事件驅(qū)動數(shù)據(jù)管理


本文是使用微服務(wù)創(chuàng)建應(yīng)用系列的第五篇文章贮聂。第一篇文章介紹了微服務(wù)架構(gòu)模式,并且討論了使用微服務(wù)的優(yōu)缺點寨辩;第二第三篇描述了微服務(wù)架構(gòu)模塊間通訊的不同方面;第四篇研究了服務(wù)發(fā)現(xiàn)中的問題歼冰。本篇中靡狞,我們從另外一個角度研究一下微服務(wù)架構(gòu)帶來的分布式數(shù)據(jù)管理問題。

1.1 微服務(wù)和分布式數(shù)據(jù)管理問題

單體式應(yīng)用一般都會有一個關(guān)系型數(shù)據(jù)庫隔嫡,由此帶來的好處是應(yīng)用可以使用 ACID transactions甸怕,可以帶來一些重要的操作特性:

原子性– 任何改變都是原子性的

一致性– 數(shù)據(jù)庫狀態(tài)一直是一致性的

隔離性– 即使交易并發(fā)執(zhí)行,看起來也是串行的

Durable– 一旦交易提交了就不可回滾

鑒于以上特性腮恩,應(yīng)用可以簡化為:開始一個交易梢杭,改變(插入,刪除秸滴,更新)很多行武契,然后提交這些交易。

使用關(guān)系型數(shù)據(jù)庫帶來另外一個優(yōu)勢在于提供SQL(功能強大荡含,可聲明的咒唆,表轉(zhuǎn)化的查詢語言)支持。用戶可以非常容易通過查詢將多個表的數(shù)據(jù)組合起來释液,RDBMS查詢調(diào)度器決定最佳實現(xiàn)方式全释,用戶不需要擔(dān)心例如如何訪問數(shù)據(jù)庫等底層問題。另外误债,因為所有應(yīng)用的數(shù)據(jù)都在一個數(shù)據(jù)庫中浸船,很容易去查詢妄迁。

然而,對于微服務(wù)架構(gòu)來說李命,數(shù)據(jù)訪問變得非常復(fù)雜登淘,這是因為數(shù)據(jù)都是微服務(wù)私有的,唯一可訪問的方式就是通過API项戴。這種打包數(shù)據(jù)訪問方式使得微服務(wù)之間松耦合形帮,并且彼此之間獨立。如果多個服務(wù)訪問同一個數(shù)據(jù)周叮,schema會更新訪問時間辩撑,并在所有服務(wù)之間進行協(xié)調(diào)。

更甚于仿耽,不同的微服務(wù)經(jīng)常使用不同的數(shù)據(jù)庫合冀。應(yīng)用會產(chǎn)生各種不同數(shù)據(jù),關(guān)系型數(shù)據(jù)庫并不一定是最佳選擇项贺。某些場景君躺,某個NoSQL數(shù)據(jù)庫可能提供更方便的數(shù)據(jù)模型,提供更加的性能和可擴展性开缎。例如棕叫,某個產(chǎn)生和查詢字符串的應(yīng)用采用例如Elasticsearch的字符搜索引擎。同樣的奕删,某個產(chǎn)生社交圖片數(shù)據(jù)的應(yīng)用可以采用圖片數(shù)據(jù)庫俺泣,例如,Neo4j完残;因此伏钠,基于微服務(wù)的應(yīng)用一般都使用SQL和NoSQL結(jié)合的數(shù)據(jù)庫,也就是被稱為polyglot persistence的方法谨设。

分區(qū)的熟掂,polyglot-persistent架構(gòu)用于存儲數(shù)據(jù)有許多優(yōu)勢,包括松耦合服務(wù)和更佳性能和可擴展性扎拣。然而赴肚,隨之而來的則是分布式數(shù)據(jù)管理帶來的挑戰(zhàn)。

第一個挑戰(zhàn)在于如何完成一筆交易的同時保持多個服務(wù)之間數(shù)據(jù)一致性二蓝。之所以會有這個問題尊蚁,我們以一個在線B2B商店為例,客戶服務(wù)維護包括客戶的各種信息侣夷,例如credit lines横朋。訂單服務(wù)管理訂單,需要驗證某個新訂單與客戶的信用限制沒有沖突百拓。在單一式應(yīng)用中琴锭,訂單服務(wù)只需要使用ACID交易就可以檢查可用信用和創(chuàng)建訂單晰甚。

相反的,微服務(wù)架構(gòu)下决帖,訂單和客戶表分別是相對應(yīng)服務(wù)的私有表厕九,如下圖所示:

訂單服務(wù)不能直接訪問客戶表,只能通過客戶服務(wù)發(fā)布的API來訪問地回。訂單服務(wù)也可以使用 distributed transactions, 也就是周知的兩階段提交 (2PC)扁远。然而,2PC在現(xiàn)在應(yīng)用中不是可選性刻像。根據(jù)CAP理論畅买,必須在可用性(availability)和ACID一致性(consistency)之間做出選擇,availability一般是更好的選擇细睡。但是谷羞,許多現(xiàn)代科技,例如許多NoSQL數(shù)據(jù)庫溜徙,并不支持2PC惊暴。在服務(wù)和數(shù)據(jù)庫之間維護數(shù)據(jù)一致性是非常根本的需求拧篮,因此我們需要找其他的方案深员。

第二個挑戰(zhàn)是如何完成從多個服務(wù)中搜索數(shù)據(jù)入宦。例如,設(shè)想應(yīng)用需要顯示客戶和他的訂單图贸。如果訂單服務(wù)提供API來接受用戶訂單信息蹂季,那么用戶可以使用類應(yīng)用型的join操作接收數(shù)據(jù)。應(yīng)用從用戶服務(wù)接受用戶信息求妹,從訂單服務(wù)接受此用戶訂單。假設(shè)佳窑,訂單服務(wù)只支持通過私有鍵(key)來查詢訂單(也許是在使用只支持基于主鍵接受的NoSQL數(shù)據(jù)庫)制恍,此時,沒有合適的方法來接收所需數(shù)據(jù)神凑。

1.2 事件驅(qū)動架構(gòu)

對許多應(yīng)用來說净神,這個解決方案就是使用事件驅(qū)動架構(gòu)(event-driven architecture)。在這種架構(gòu)中溉委,當(dāng)某件重要事情發(fā)生時鹃唯,微服務(wù)會發(fā)布一個事件,例如更新一個業(yè)務(wù)實體瓣喊。當(dāng)訂閱這些事件的微服務(wù)接收此事件時坡慌,就可以更新自己的業(yè)務(wù)實體,也可能會引發(fā)更多的時間發(fā)布藻三。

可以使用事件來實現(xiàn)跨多服務(wù)的業(yè)務(wù)交易洪橘。交易一般由一系列步驟構(gòu)成跪者,每一步驟都由一個更新業(yè)務(wù)實體的微服務(wù)和發(fā)布激活下一步驟的事件構(gòu)成。下圖展現(xiàn)如何使用事件驅(qū)動方法熄求,在創(chuàng)建訂單時檢查信用可用度渣玲,微服務(wù)通過消息代理(Messsage Broker)來交換事件。

訂單服務(wù)創(chuàng)建一個帶有NEW狀態(tài)的Order (訂單)弟晚,發(fā)布了一個“Order Created Event(創(chuàng)建訂單)”的事件忘衍。

客戶服務(wù)消費Order Created Event事件,為此訂單預(yù)留信用卿城,發(fā)布“Credit Reserved Event(信用預(yù)留)”事件

訂單服務(wù)消費Credit Reserved Event枚钓,改變訂單的狀態(tài)為OPEN

更復(fù)雜的場景可以引入更多步驟,例如在檢查用戶信用的同時預(yù)留庫存等藻雪。

考慮到(a)每個服務(wù)原子性更新數(shù)據(jù)庫和發(fā)布事件秘噪,然后,(b)消息代理確保事件傳遞至少一次勉耀,然后可以跨多個服務(wù)完成業(yè)務(wù)交易(此交易不是ACID交易)指煎。這種模式提供弱確定性,例如最終一致性 eventual consistency便斥。這種交易類型被稱作 BASE model至壤。

亦可以使用事件來維護不同微服務(wù)擁有數(shù)據(jù)預(yù)連接(pre-join)的實現(xiàn)視圖。維護此視圖的服務(wù)訂閱相關(guān)事件并且更新視圖枢纠。例如像街,客戶訂單視圖更新服務(wù)(維護客戶訂單視圖)會訂閱由客戶服務(wù)和訂單服務(wù)發(fā)布的事件。

當(dāng)客戶訂單視圖更新服務(wù)收到客戶或者訂單事件晋渺,就會更新 客戶訂單視圖數(shù)據(jù)集镰绎。可以使用文檔數(shù)據(jù)庫(例如MongoDB)來實現(xiàn)客戶訂單視圖木西,為每個用戶存儲一個文檔畴栖。客戶訂單視圖查詢服務(wù)負責(zé)響應(yīng)對客戶以及最近訂單(通過查詢客戶訂單視圖數(shù)據(jù)集)的查詢八千。

事件驅(qū)動架構(gòu)也是既有優(yōu)點也有缺點吗讶,此架構(gòu)可以使得交易跨多個服務(wù)且提供最終一致性,并且可以使應(yīng)用維護最終視圖恋捆;而缺點在于編程模式比ACID交易模式更加復(fù)雜:為了從應(yīng)用層級失效中恢復(fù)照皆,還需要完成補償性交易,例如沸停,如果信用檢查不成功則必須取消訂單膜毁;另外,應(yīng)用必須應(yīng)對不一致的數(shù)據(jù),這是因為臨時(in-flight)交易造成的改變是可見的爽茴,另外當(dāng)應(yīng)用讀取未更新的最終視圖時也會遇見數(shù)據(jù)不一致問題葬凳。另外一個缺點在于訂閱者必須檢測和忽略冗余事件。

1.3 原子操作Achieving Atomicity

事件驅(qū)動架構(gòu)還會碰到數(shù)據(jù)庫更新和發(fā)布事件原子性問題室奏。例如火焰,訂單服務(wù)必須向ORDER表插入一行,然后發(fā)布Order Created event胧沫,這兩個操作需要原子性昌简。如果更新數(shù)據(jù)庫后,服務(wù)癱了(crashes)造成事件未能發(fā)布绒怨,系統(tǒng)變成不一致狀態(tài)纯赎。確保原子操作的標(biāo)準(zhǔn)方式是使用一個分布式交易,其中包括數(shù)據(jù)庫和消息代理南蹂。然而犬金,基于以上描述的CAP理論,這卻并不是我們想要的六剥。

1.3.1 使用本地交易發(fā)布事件

獲得原子性的一個方法是對發(fā)布事件應(yīng)用采用multi-step process involving only local transactions晚顷,技巧在于一個EVENT表,此表在存儲業(yè)務(wù)實體數(shù)據(jù)庫中起到消息列表功能疗疟。應(yīng)用發(fā)起一個(本地)數(shù)據(jù)庫交易该默,更新業(yè)務(wù)實體狀態(tài),向EVENT表中插入一個事件策彤,然后提交此次交易栓袖。另外一個獨立應(yīng)用進程或者線程查詢此EVENT表,向消息代理發(fā)布事件店诗,然后使用本地交易標(biāo)志此事件為已發(fā)布裹刮,如下圖所示:

訂單服務(wù)向ORDER表插入一行,然后向EVENT表中插入Order Created event庞瘸,事件發(fā)布線程或者進程查詢EVENT表捧弃,請求未發(fā)布事件,發(fā)布他們恕洲,然后更新EVENT表標(biāo)志此事件為已發(fā)布塔橡。

此方法也是優(yōu)缺點都有梅割。優(yōu)點是可以確保事件發(fā)布不依賴于2PC霜第,應(yīng)用發(fā)布業(yè)務(wù)層級事件而不需要推斷他們發(fā)生了什么;而缺點在于此方法由于開發(fā)人員必須牢記發(fā)布事件户辞,因此有可能出現(xiàn)錯誤泌类。另外此方法對于某些使用NoSQL數(shù)據(jù)庫的應(yīng)用是個挑戰(zhàn),因為NoSQL本身交易和查詢能力有限。

此方法因為應(yīng)用采用了本地交易更新狀態(tài)和發(fā)布事件而不需要2PC刃榨,現(xiàn)在再看看另外一種應(yīng)用簡單更新狀態(tài)獲得原子性的方法弹砚。

1.3.2 挖掘數(shù)據(jù)庫交易日志

另外一種不需要2PC而獲得線程或者進程發(fā)布事件原子性的方式就是挖掘數(shù)據(jù)庫交易或者提交日志。應(yīng)用更新數(shù)據(jù)庫枢希,在數(shù)據(jù)庫交易日志中產(chǎn)生變化桌吃,交易日志挖掘進程或者線程讀這些交易日志,將日志發(fā)布給消息代理苞轿。如下圖所見:

此方法的例子如LinkedIn Databus 項目茅诱,Databus 挖掘Oracle交易日志,根據(jù)變化發(fā)布事件搬卒,LinkedIn使用Databus來保證系統(tǒng)內(nèi)各記錄之間的一致性瑟俭。

另外的例子如:AWS的 streams mechanism in AWS DynamoDB,是一個可管理的NoSQL數(shù)據(jù)庫契邀,一個DynamoDB流是由過去24小時對數(shù)據(jù)庫表基于時序的變化(創(chuàng)建摆寄,更新和刪除操作),應(yīng)用可以從流中讀取這些變化坯门,然后以事件方式發(fā)布這些變化微饥。

交易日志挖掘也是優(yōu)缺點并存。優(yōu)點是確保每次更新發(fā)布事件不依賴于2PC田盈。交易日志挖掘可以通過將發(fā)布事件和應(yīng)用業(yè)務(wù)邏輯分離開得到簡化畜号;而主要缺點在于交易日志對不同數(shù)據(jù)庫有不同格式,甚至不同數(shù)據(jù)庫版本也有不同格式允瞧;而且很難從底層交易日志更新記錄轉(zhuǎn)換為高層業(yè)務(wù)事件简软。

交易日志挖掘方法通過應(yīng)用直接更新數(shù)據(jù)庫而不需要2PC介入。下面我們再看一種完全不同的方法:不需要更新只依賴事件的方法述暂。

1.3.3 使用事件源

Event sourcing (事件源)通過使用根本不同的事件中心方式來獲得不需2PC的原子性痹升,保證業(yè)務(wù)實體的一致性。 這種應(yīng)用保存業(yè)務(wù)實體一系列狀態(tài)改變事件畦韭,而不是存儲實體現(xiàn)在的狀態(tài)疼蛾。應(yīng)用可以通過重放事件來重建實體現(xiàn)在狀態(tài)。只要業(yè)務(wù)實體發(fā)生變化艺配,新事件就會添加到時間表中察郁。因為保存事件是單一操作,因此肯定是原子性的转唉。

為了理解事件源工作方式皮钠,考慮事件實體作為一個例子。傳統(tǒng)方式中赠法,每個訂單映射為ORDER表中一行麦轰,例如在ORDER_LINE_ITEM表中。但是對于事件源方式,訂單服務(wù)以事件狀態(tài)改變方式存儲一個訂單:創(chuàng)建的款侵,已批準(zhǔn)的末荐,已發(fā)貨的,取消的新锈;每個事件包括足夠數(shù)據(jù)來重建訂單狀態(tài)甲脏。

事件是長期保存在事件數(shù)據(jù)庫中,提供API添加和獲取實體事件妹笆。事件存儲跟之前描述的消息代理類似剃幌,提供API來訂閱事件。事件存儲將事件遞送到所有感興趣的訂閱者晾浴,事件存儲是事件驅(qū)動微服務(wù)架構(gòu)的基干负乡。

事件源方法有很多優(yōu)點:解決了事件驅(qū)動架構(gòu)關(guān)鍵問題,使得只要有狀態(tài)變化就可以可靠地發(fā)布事件脊凰,也就解決了微服務(wù)架構(gòu)中數(shù)據(jù)一致性問題抖棘。另外,因為是持久化事件而不是對象狸涌,也就避免了object relational impedance mismatch problem切省。

數(shù)據(jù)源方法提供了100%可靠的業(yè)務(wù)實體變化監(jiān)控日志,使得獲取任何時點實體狀態(tài)成為可能帕胆。另外朝捆,事件源方法可以使得業(yè)務(wù)邏輯可以由事件交換的松耦合業(yè)務(wù)實體構(gòu)成。這些優(yōu)勢使得單體應(yīng)用移植到微服務(wù)架構(gòu)變的相對容易懒豹。

事件源方法也有不少缺點芙盘,因為采用不同或者不太熟悉的變成模式,使得重新學(xué)習(xí)不太容易脸秽;事件存儲只支持主鍵查詢業(yè)務(wù)實體儒老,必須使用 Command Query Responsibility Segregation (CQRS) 來完成查詢業(yè)務(wù),因此记餐,應(yīng)用必須處理最終一致數(shù)據(jù)驮樊。

1.4 總結(jié)

在微服務(wù)架構(gòu)中,每個微服務(wù)都有自己私有的數(shù)據(jù)集片酝。不同微服務(wù)可能使用不同的SQL或者NoSQL數(shù)據(jù)庫囚衔。盡管數(shù)據(jù)庫架構(gòu)有很強的優(yōu)勢,但是也面對數(shù)據(jù)分布式管理的挑戰(zhàn)雕沿。第一個挑戰(zhàn)就是如何在多服務(wù)之間維護業(yè)務(wù)交易一致性练湿;第二個挑戰(zhàn)是如何從多服務(wù)環(huán)境中獲取一致性數(shù)據(jù)。

最佳解決辦法是采用事件驅(qū)動架構(gòu)晦炊。其中碰到的一個挑戰(zhàn)是如何原子性的更新狀態(tài)和發(fā)布事件鞠鲜。有幾種方法可以解決此問題,包括將數(shù)據(jù)庫視為消息隊列断国、交易日志挖掘和事件源贤姆。

在未來的博客中,將會跟深入探討微服務(wù)的其他方面稳衬。

@Container容器技術(shù)大會正在火熱報名中霞捡,知名公司的Docker、Kubernetes薄疚、Mesos應(yīng)用案例碧信,點擊下圖可查看大會具體內(nèi)容。

點擊左下角閱讀原文鏈接可進入大會官網(wǎng)街夭。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末砰碴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子板丽,更是在濱河造成了極大的恐慌呈枉,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件埃碱,死亡現(xiàn)場離奇詭異猖辫,居然都是意外死亡,警方通過查閱死者的電腦和手機砚殿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門啃憎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人似炎,你說我怎么就攤上這事辛萍。” “怎么了羡藐?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵叹阔,是天一觀的道長。 經(jīng)常有香客問我传睹,道長耳幢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任欧啤,我火速辦了婚禮睛藻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘邢隧。我一直安慰自己店印,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布倒慧。 她就那樣靜靜地躺著按摘,像睡著了一般包券。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上炫贤,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天溅固,我揣著相機與錄音,去河邊找鬼兰珍。 笑死侍郭,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掠河。 我是一名探鬼主播亮元,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼唠摹!你這毒婦竟也來了爆捞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤勾拉,失蹤者是張志新(化名)和其女友劉穎嵌削,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體望艺,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡苛秕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了找默。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艇劫。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖惩激,靈堂內(nèi)的尸體忽然破棺而出店煞,到底是詐尸還是另有隱情,我是刑警寧澤风钻,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布顷蟀,位于F島的核電站,受9級特大地震影響骡技,放射性物質(zhì)發(fā)生泄漏鸣个。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一布朦、第九天 我趴在偏房一處隱蔽的房頂上張望囤萤。 院中可真熱鬧,春花似錦是趴、人聲如沸涛舍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽富雅。三九已至掸驱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間没佑,已是汗流浹背毕贼。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留图筹,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓让腹,卻偏偏與公主長得像远剩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子骇窍,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

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