微服務實踐(五):微服務的事件驅動數據管理

微服務實踐(五):微服務的事件驅動數據管理


本文是使用微服務創建應用系列的第五篇文章。第一篇文章介紹了微服務架構模式,并且討論了使用微服務的優缺點;第二第三篇描述了微服務架構模塊間通訊的不同方面;第四篇研究了服務發現中的問題。本篇中,我們從另外一個角度研究一下微服務架構帶來的分布式數據管理問題。

1.1 微服務和分布式數據管理問題

單體式應用一般都會有一個關系型數據庫,由此帶來的好處是應用可以使用 ACID transactions,可以帶來一些重要的操作特性:

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

一致性– 數據庫狀態一直是一致性的

隔離性– 即使交易并發執行,看起來也是串行的

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

鑒于以上特性,應用可以簡化為:開始一個交易,改變(插入,刪除,更新)很多行,然后提交這些交易。

使用關系型數據庫帶來另外一個優勢在于提供SQL(功能強大,可聲明的,表轉化的查詢語言)支持。用戶可以非常容易通過查詢將多個表的數據組合起來,RDBMS查詢調度器決定最佳實現方式,用戶不需要擔心例如如何訪問數據庫等底層問題。另外,因為所有應用的數據都在一個數據庫中,很容易去查詢。

然而,對于微服務架構來說,數據訪問變得非常復雜,這是因為數據都是微服務私有的,唯一可訪問的方式就是通過API。這種打包數據訪問方式使得微服務之間松耦合,并且彼此之間獨立。如果多個服務訪問同一個數據,schema會更新訪問時間,并在所有服務之間進行協調。

更甚于,不同的微服務經常使用不同的數據庫。應用會產生各種不同數據,關系型數據庫并不一定是最佳選擇。某些場景,某個NoSQL數據庫可能提供更方便的數據模型,提供更加的性能和可擴展性。例如,某個產生和查詢字符串的應用采用例如Elasticsearch的字符搜索引擎。同樣的,某個產生社交圖片數據的應用可以采用圖片數據庫,例如,Neo4j;因此,基于微服務的應用一般都使用SQL和NoSQL結合的數據庫,也就是被稱為polyglot persistence的方法。

分區的,polyglot-persistent架構用于存儲數據有許多優勢,包括松耦合服務和更佳性能和可擴展性。然而,隨之而來的則是分布式數據管理帶來的挑戰。

第一個挑戰在于如何完成一筆交易的同時保持多個服務之間數據一致性。之所以會有這個問題,我們以一個在線B2B商店為例,客戶服務維護包括客戶的各種信息,例如credit lines。訂單服務管理訂單,需要驗證某個新訂單與客戶的信用限制沒有沖突。在單一式應用中,訂單服務只需要使用ACID交易就可以檢查可用信用和創建訂單。

相反的,微服務架構下,訂單和客戶表分別是相對應服務的私有表,如下圖所示:

訂單服務不能直接訪問客戶表,只能通過客戶服務發布的API來訪問。訂單服務也可以使用 distributed transactions, 也就是周知的兩階段提交 (2PC)。然而,2PC在現在應用中不是可選性。根據CAP理論,必須在可用性(availability)和ACID一致性(consistency)之間做出選擇,availability一般是更好的選擇。但是,許多現代科技,例如許多NoSQL數據庫,并不支持2PC。在服務和數據庫之間維護數據一致性是非常根本的需求,因此我們需要找其他的方案。

第二個挑戰是如何完成從多個服務中搜索數據。例如,設想應用需要顯示客戶和他的訂單。如果訂單服務提供API來接受用戶訂單信息,那么用戶可以使用類應用型的join操作接收數據。應用從用戶服務接受用戶信息,從訂單服務接受此用戶訂單。假設,訂單服務只支持通過私有鍵(key)來查詢訂單(也許是在使用只支持基于主鍵接受的NoSQL數據庫),此時,沒有合適的方法來接收所需數據。

1.2 事件驅動架構

對許多應用來說,這個解決方案就是使用事件驅動架構(event-driven architecture)。在這種架構中,當某件重要事情發生時,微服務會發布一個事件,例如更新一個業務實體。當訂閱這些事件的微服務接收此事件時,就可以更新自己的業務實體,也可能會引發更多的時間發布。

可以使用事件來實現跨多服務的業務交易。交易一般由一系列步驟構成,每一步驟都由一個更新業務實體的微服務和發布激活下一步驟的事件構成。下圖展現如何使用事件驅動方法,在創建訂單時檢查信用可用度,微服務通過消息代理(Messsage Broker)來交換事件。

訂單服務創建一個帶有NEW狀態的Order (訂單),發布了一個“Order Created Event(創建訂單)”的事件。

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

訂單服務消費Credit Reserved Event,改變訂單的狀態為OPEN

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

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

亦可以使用事件來維護不同微服務擁有數據預連接(pre-join)的實現視圖。維護此視圖的服務訂閱相關事件并且更新視圖。例如,客戶訂單視圖更新服務(維護客戶訂單視圖)會訂閱由客戶服務和訂單服務發布的事件。

當客戶訂單視圖更新服務收到客戶或者訂單事件,就會更新 客戶訂單視圖數據集。可以使用文檔數據庫(例如MongoDB)來實現客戶訂單視圖,為每個用戶存儲一個文檔。客戶訂單視圖查詢服務負責響應對客戶以及最近訂單(通過查詢客戶訂單視圖數據集)的查詢。

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

1.3 原子操作Achieving Atomicity

事件驅動架構還會碰到數據庫更新和發布事件原子性問題。例如,訂單服務必須向ORDER表插入一行,然后發布Order Created event,這兩個操作需要原子性。如果更新數據庫后,服務癱了(crashes)造成事件未能發布,系統變成不一致狀態。確保原子操作的標準方式是使用一個分布式交易,其中包括數據庫和消息代理。然而,基于以上描述的CAP理論,這卻并不是我們想要的。

1.3.1 使用本地交易發布事件

獲得原子性的一個方法是對發布事件應用采用multi-step process involving only local transactions,技巧在于一個EVENT表,此表在存儲業務實體數據庫中起到消息列表功能。應用發起一個(本地)數據庫交易,更新業務實體狀態,向EVENT表中插入一個事件,然后提交此次交易。另外一個獨立應用進程或者線程查詢此EVENT表,向消息代理發布事件,然后使用本地交易標志此事件為已發布,如下圖所示:

訂單服務向ORDER表插入一行,然后向EVENT表中插入Order Created event,事件發布線程或者進程查詢EVENT表,請求未發布事件,發布他們,然后更新EVENT表標志此事件為已發布。

此方法也是優缺點都有。優點是可以確保事件發布不依賴于2PC,應用發布業務層級事件而不需要推斷他們發生了什么;而缺點在于此方法由于開發人員必須牢記發布事件,因此有可能出現錯誤。另外此方法對于某些使用NoSQL數據庫的應用是個挑戰,因為NoSQL本身交易和查詢能力有限。

此方法因為應用采用了本地交易更新狀態和發布事件而不需要2PC,現在再看看另外一種應用簡單更新狀態獲得原子性的方法。

1.3.2 挖掘數據庫交易日志

另外一種不需要2PC而獲得線程或者進程發布事件原子性的方式就是挖掘數據庫交易或者提交日志。應用更新數據庫,在數據庫交易日志中產生變化,交易日志挖掘進程或者線程讀這些交易日志,將日志發布給消息代理。如下圖所見:

此方法的例子如LinkedIn Databus 項目,Databus 挖掘Oracle交易日志,根據變化發布事件,LinkedIn使用Databus來保證系統內各記錄之間的一致性。

另外的例子如:AWS的 streams mechanism in AWS DynamoDB,是一個可管理的NoSQL數據庫,一個DynamoDB流是由過去24小時對數據庫表基于時序的變化(創建,更新和刪除操作),應用可以從流中讀取這些變化,然后以事件方式發布這些變化。

交易日志挖掘也是優缺點并存。優點是確保每次更新發布事件不依賴于2PC。交易日志挖掘可以通過將發布事件和應用業務邏輯分離開得到簡化;而主要缺點在于交易日志對不同數據庫有不同格式,甚至不同數據庫版本也有不同格式;而且很難從底層交易日志更新記錄轉換為高層業務事件。

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

1.3.3 使用事件源

Event sourcing (事件源)通過使用根本不同的事件中心方式來獲得不需2PC的原子性,保證業務實體的一致性。 這種應用保存業務實體一系列狀態改變事件,而不是存儲實體現在的狀態。應用可以通過重放事件來重建實體現在狀態。只要業務實體發生變化,新事件就會添加到時間表中。因為保存事件是單一操作,因此肯定是原子性的。

為了理解事件源工作方式,考慮事件實體作為一個例子。傳統方式中,每個訂單映射為ORDER表中一行,例如在ORDER_LINE_ITEM表中。但是對于事件源方式,訂單服務以事件狀態改變方式存儲一個訂單:創建的,已批準的,已發貨的,取消的;每個事件包括足夠數據來重建訂單狀態。

事件是長期保存在事件數據庫中,提供API添加和獲取實體事件。事件存儲跟之前描述的消息代理類似,提供API來訂閱事件。事件存儲將事件遞送到所有感興趣的訂閱者,事件存儲是事件驅動微服務架構的基干。

事件源方法有很多優點:解決了事件驅動架構關鍵問題,使得只要有狀態變化就可以可靠地發布事件,也就解決了微服務架構中數據一致性問題。另外,因為是持久化事件而不是對象,也就避免了object relational impedance mismatch problem。

數據源方法提供了100%可靠的業務實體變化監控日志,使得獲取任何時點實體狀態成為可能。另外,事件源方法可以使得業務邏輯可以由事件交換的松耦合業務實體構成。這些優勢使得單體應用移植到微服務架構變的相對容易。

事件源方法也有不少缺點,因為采用不同或者不太熟悉的變成模式,使得重新學習不太容易;事件存儲只支持主鍵查詢業務實體,必須使用 Command Query Responsibility Segregation (CQRS) 來完成查詢業務,因此,應用必須處理最終一致數據。

1.4 總結

在微服務架構中,每個微服務都有自己私有的數據集。不同微服務可能使用不同的SQL或者NoSQL數據庫。盡管數據庫架構有很強的優勢,但是也面對數據分布式管理的挑戰。第一個挑戰就是如何在多服務之間維護業務交易一致性;第二個挑戰是如何從多服務環境中獲取一致性數據。

最佳解決辦法是采用事件驅動架構。其中碰到的一個挑戰是如何原子性的更新狀態和發布事件。有幾種方法可以解決此問題,包括將數據庫視為消息隊列、交易日志挖掘和事件源。

在未來的博客中,將會跟深入探討微服務的其他方面。

@Container容器技術大會正在火熱報名中,知名公司的Docker、Kubernetes、Mesos應用案例,點擊下圖可查看大會具體內容。

點擊左下角閱讀原文鏈接可進入大會官網。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容