場景
假設我們正在使用微服務架構(gòu)模式開發(fā)一個在線商店應用漠趁。大多數(shù)的服務都需要持久化數(shù)據(jù)到某些數(shù)據(jù)庫中扁凛。例如,訂單服務存儲訂單信息闯传,用戶服務存儲用戶信息令漂。
問題
微服務應用中的數(shù)據(jù)庫架構(gòu)是什么樣的?
約束條件
服務必須是松耦合的,這樣才能夠獨立地開發(fā)叠必、部署和擴展這些微服務荚孵。
必須保持某些跨多個服務的業(yè)務事務的不變性。例如纬朝,下訂單用例必須驗證新訂單不會超出用戶信用額度限制收叶。某些業(yè)務事務必須更新由多個服務擁有的數(shù)據(jù)。
某些業(yè)務事務需要查詢由不同服務擁有的數(shù)據(jù)共苛。例如判没,查看可用信用額度用例必須查詢用戶服務來查找信用額度限制以及訂單服務來計算未完成訂單總數(shù)量。
某些查詢必須關聯(lián)由多個服務擁有的數(shù)據(jù)隅茎。例如澄峰,查找屬于特定區(qū)域的用戶以及他們最近一段時間的訂單,需要關聯(lián)用戶和訂單辟犀。
有時候為了擴展俏竞,數(shù)據(jù)庫必須可以被復制和共享。
不同服務有不同的數(shù)據(jù)存儲要求堂竟。對于某些服務魂毁,關系型數(shù)據(jù)庫是最好的選擇。其它服務可能需要NoSQL數(shù)據(jù)庫比如MongoDB(擅長存儲復雜出嘹、非結(jié)構(gòu)化數(shù)據(jù))或Neo4J(能高效地存儲以及查詢圖形數(shù)據(jù))席楚。
解決方案
保持每個微服務的持久化數(shù)據(jù)是私有的并且只能通過該服務的API訪問。下圖展示了該模式的結(jié)構(gòu):
服務的數(shù)據(jù)庫實際上作為該服務實現(xiàn)的一部分税稼。它不能直接地被其它服務訪問烦秩。
保持服務持久化數(shù)據(jù)的私有有一些不同的方式。為每個服務提供一個數(shù)據(jù)庫服務器不是必要郎仆。例如闻镶,如果使用關系型數(shù)據(jù)庫,可以使用下面的三種方式:
Private-tables-per-service —— 每個服務擁有一個必須只能被該服務訪問的表集
Schema-per-service —— 每個服務都有一個私有的數(shù)據(jù)庫schema
Database-server-per-service —— 每個服務都有自己的數(shù)據(jù)庫服務器
Private-tables-per-service和schema-per-service的開銷是最低的丸升。使用schema-per-service比較有吸引力铆农,因為該方式讓所有權比較清楚。某些高吞吐量服務可能需要它們自己的數(shù)據(jù)庫服務器狡耻。
創(chuàng)建一些邊界壁壘來加強模塊化是個好主意墩剖。例如,可以給每個服務分配不同的數(shù)據(jù)庫用戶ID夷狰,并且使用數(shù)據(jù)庫訪問控制機制比如授權岭皂。沒有某種邊界壁壘來實施封裝,開發(fā)人員總會被誘惑去繞過某個服務的API而去直接訪問它的數(shù)據(jù)沼头。
影響
每個服務一個數(shù)據(jù)庫的好處:
有利于確保服務是松耦合的爷绘。某個服務的數(shù)據(jù)庫發(fā)生改變不影響其它服務书劝。
每個服務能夠使用最合適它們需求的數(shù)據(jù)庫類型。例如土至,某個服務處理文本搜索购对,可以使用ElasticSearch。處理社交圖數(shù)據(jù)的服務可以使用Neo4j陶因。
弊端:
實現(xiàn)跨不同服務的事務很復雜骡苞。由于CAP理論,最好避免分布式事務楷扬。此外解幽,很多現(xiàn)代(NoSQL)數(shù)據(jù)庫不支持分布式事務。最好的解決方案是使用Saga模式(事件履歷模式)烘苹。當服務更新數(shù)據(jù)時躲株,服務發(fā)布事件。其它的服務訂閱這些事件并且更新它們的數(shù)據(jù)作為回應镣衡。
目前在多個數(shù)據(jù)庫中實現(xiàn)關聯(lián)查詢是很有挑戰(zhàn)的霜定。
一些解決方案:
API組合 —— 應用處理關聯(lián)而不是數(shù)據(jù)庫捆探。例如站粟,每個服務(或者API網(wǎng)關)可以檢索某個用戶和他的訂單,首先從用戶服務檢索用戶助被,然后查詢訂單服務切诀,返回用戶最近一段時間的訂單。
命令與查詢職責分離(CQRS)—— 維護一個或多個包含不同服務的數(shù)據(jù)的物化視圖(materialized view)丰滑。這些視圖由訂閱事件的服務保有倒庵。例如,通過維護一個關聯(lián)用戶和訂單的視圖擎宝,在線商店能夠執(zhí)行某個查詢?nèi)フ页瞿硞€特定區(qū)域的用戶和他們最近一段時間的訂單绍申。該視圖由訂閱用戶和訂單事件的服務更新顾彰。
管理不同SQL和NoSQL數(shù)據(jù)庫的復雜性