溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

微服務(wù)的數(shù)據(jù)庫設(shè)計是怎樣的

發(fā)布時間:2021-12-02 11:14:32 來源:億速云 閱讀:150 作者:柒染 欄目:數(shù)據(jù)庫

這篇文章給大家介紹微服務(wù)的數(shù)據(jù)庫設(shè)計是怎樣的,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

單獨(dú)的數(shù)據(jù)庫:

微服務(wù)設(shè)計的一個關(guān)鍵是數(shù)據(jù)庫設(shè)計,基本原則是每個服務(wù)都有自己單獨(dú)的數(shù)據(jù)庫,而且只有微服務(wù)本身可以訪問這個數(shù)據(jù)庫。它是基于下面三個原因。

  • 優(yōu)化服務(wù)接口:微服務(wù)之間的接口越小越好,最好只有服務(wù)調(diào)用接口(RPC或消息),沒有其他接口。如果微服務(wù)不能獨(dú)享自己的數(shù)據(jù)庫,那么數(shù)據(jù)庫也變成了接口的一部分,這大大拓展了接口范圍。

  • 錯誤診斷:生產(chǎn)環(huán)境中的錯誤大部分都是和數(shù)據(jù)庫有關(guān)的,要么是數(shù)據(jù)出了問題,要么是數(shù)據(jù)庫的使用方式出了問題。當(dāng)你不能完全控制數(shù)據(jù)庫的訪問時,會有各種各樣的錯誤發(fā)生。它可能是別的程序直接連到你的數(shù)據(jù)庫或者是其他部門直接用客戶端訪問數(shù)據(jù)庫的數(shù)據(jù),而這些都是在程序中查不到的,增加了錯誤排查難度。如果是程序中的問題,只要修改了代碼,那么這個錯誤就不會再有。而上面提到的錯誤,你永遠(yuǎn)都沒法預(yù)測它們什么時候還會再次發(fā)生。

  • 性能調(diào)優(yōu):性能調(diào)優(yōu)也是一樣,你需要對數(shù)據(jù)庫有全權(quán)控制才能保證它的性能。如果其他部門一定要訪問數(shù)據(jù)庫,而且只是查詢的話,那么可以另外創(chuàng)建一份只讀數(shù)據(jù)庫,讓他們在另一個庫中查詢,這樣才不會影響到你的庫。

理想的設(shè)計是你的數(shù)據(jù)庫只有你的服務(wù)能訪問,你也只調(diào)用自己數(shù)據(jù)庫中的數(shù)據(jù),所有對別的微服務(wù)的訪問都通過服務(wù)調(diào)用來實(shí)現(xiàn)。當(dāng)然,在實(shí)際應(yīng)用中,單純的服務(wù)調(diào)用可能不能滿足性能或其他要求,不同的微服務(wù)都多少需要共享一些數(shù)據(jù)。

共享數(shù)據(jù):

微服務(wù)之間的數(shù)據(jù)共享可以有下四種方式。

靜態(tài)表:

有一些靜態(tài)的數(shù)據(jù)庫表,例如國家,可能會被很多程序用到,而且程序內(nèi)部需要對國家這個表做連接(join)生成最終用戶展示數(shù)據(jù),這樣用微服務(wù)調(diào)用的方式就效率不高,影響性能。一個辦法是在每個微服務(wù)中配置一個這樣的表,它是只讀的,這樣就可以做數(shù)據(jù)庫連接了。當(dāng)然你需要保證數(shù)據(jù)同步。這個方案在多數(shù)情況下都是可以接受的,因為以下兩點(diǎn):

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 靜態(tài)的數(shù)據(jù)庫表結(jié)構(gòu)基本不變:因為一旦表結(jié)構(gòu)變了,你不但要更改所有微服務(wù)的數(shù)據(jù)庫表,還要修改所有微服務(wù)的程序。

  3. 數(shù)據(jù)庫表中的數(shù)據(jù)變化不頻繁:這樣數(shù)據(jù)同步的工作量不大。另外當(dāng)你同步數(shù)據(jù)庫時總會有延遲,如果數(shù)據(jù)變化不頻繁那么你有很多同步方式可供選擇。

只讀業(yè)務(wù)數(shù)據(jù)訪問:

如果你需要讀取別的數(shù)據(jù)庫里的動態(tài)業(yè)務(wù)數(shù)據(jù),  理想的方式是服務(wù)調(diào)用。如果你只是調(diào)用其他微服務(wù)做一些計算,一般情況下性能都是可以接受的。如果你需要做數(shù)據(jù)的連接,那么你可以用程序代碼來做,而不是用SQL語句。如果測試之后性能不能滿足要求,那你可以考慮在自己的數(shù)據(jù)庫里建一套只讀數(shù)據(jù)表。數(shù)據(jù)同步方式大致有兩種。如果是事件驅(qū)動方式,就用發(fā)消息的方式進(jìn)行同步,如果是RPC方式,就用數(shù)據(jù)庫本身提供的同步方式或者第三方同步軟件。

通常情況下,你可能只需要其他數(shù)據(jù)庫的幾張表,每張表只需要幾個字段。這時,其他數(shù)據(jù)庫是數(shù)據(jù)的最終來源,控制所有寫操作以及相應(yīng)的業(yè)務(wù)驗證邏輯,我們叫它主表。你的只讀庫可以叫從表。  當(dāng)一條數(shù)據(jù)寫入主表后,會發(fā)一條廣播消息,所有擁有從表的微服務(wù)監(jiān)聽消息并更新只讀表中的數(shù)據(jù)。但這時你要特別小心,因為它的危險性要比靜態(tài)表大得多。第一它的表結(jié)構(gòu)變更會更頻繁,而且它的變更完全不受你控制。第二業(yè)務(wù)數(shù)據(jù)不像靜態(tài)表,它是經(jīng)常更新的,這樣對數(shù)據(jù)同步的要求就比較高。要根據(jù)具體的業(yè)務(wù)需求來決定多大的延遲是可以接受的。

另外它還有兩個問題:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 數(shù)據(jù)的容量:數(shù)據(jù)庫中的數(shù)據(jù)量是影響性能的主要因素。因為這個數(shù)據(jù)是外來的,不利于掌握它的流量規(guī)律,很難進(jìn)行容量規(guī)劃,也不能更好地進(jìn)行性能調(diào)優(yōu)。

  3. 接口外泄:微服務(wù)之間的接口本來只有服務(wù)調(diào)用接口,這時你可以對內(nèi)部程序和數(shù)據(jù)庫做任何更改,而不影響其他服務(wù)。現(xiàn)在數(shù)據(jù)庫表結(jié)構(gòu)也變成了接口的一部分。接口一旦發(fā)布之后,基本是不能更改的,這大大限制了你的靈活性。幸運(yùn)的是因為另外建了一套表,有了一個緩沖,當(dāng)主表修改時,從表也許不需要同步更新。

除非你能用服務(wù)調(diào)用(沒有本地只讀數(shù)據(jù)庫)的方式完成所有功能,不然不管你是用RPC方式還是事件驅(qū)動方式進(jìn)行微服務(wù)集成,上面提到的問題都是不可避免的。但是你可以通過合理規(guī)劃數(shù)據(jù)庫更改,來減少上面問題帶來的影響,下面將會詳細(xì)講解。

讀寫業(yè)務(wù)數(shù)據(jù)訪問:

這是最復(fù)雜的一種情況。一般情況下,你有一個表是主表,而其他表是從表。主表包含主要信息,而且這些主要信息被復(fù)制到從表,但微服務(wù)會有額外字段需要寫入從表。這樣本地微服務(wù)對從表就既有讀也有寫的操作。而且主表和從表有一個先后次序的關(guān)系。從表的主鍵來源于主表,因此一定先有主表,再有從表。

微服務(wù)的數(shù)據(jù)庫設(shè)計是怎樣的

上圖是例子。假設(shè)我們有兩個與電影有關(guān)的微服務(wù),一個是電影論壇,用戶可以發(fā)表對電影的評論。另一個是電影商店。“movie”是共享表,左邊的一個是電影論壇庫,它的“movie”表是主表。右邊的是電影商店庫,它的“movie”表是從表。它們共享“id”字段(主鍵)。主表是數(shù)據(jù)的主要來源,但從表里的“quantity”和“price”字段主表里面沒有。主表插入數(shù)據(jù)后,發(fā)消息,從表接到消息,插入一條數(shù)據(jù)到本地“movie”表。并且從表還會修改表里的“quantity”和“price”字段。在這種情況下,要給每一個字段分配一個唯一源頭(微服務(wù)),只有源頭才有權(quán)利主動更改字段,其他微服務(wù)只能被動更改(接收源頭發(fā)出的更改消息之后再改)。在本例子中,  “quantity”和“price”字段的源頭是右邊的表,其他的字段的源頭都是左邊的表。本例子中“quantity”和“price”只在從表中存在,因此數(shù)據(jù)寫入是單向的,方向是主表到從表。如果主表也需要這些字段,那么它們還要被回寫,那數(shù)據(jù)寫入就變成雙向的。

直接訪問其它數(shù)據(jù)庫:

這種方式是要絕對禁止的。生產(chǎn)環(huán)境中的許多程序錯誤和性能問題都是由這種方式產(chǎn)生的。上面的三種方式由于是另外新建了本地只讀數(shù)據(jù)庫表,產(chǎn)生了數(shù)據(jù)庫的物理隔離,這樣一個數(shù)據(jù)庫的性能問題不會影響到另一個。另外,當(dāng)主庫中的表結(jié)構(gòu)更改時,你可以暫時保持從庫中的表不變,這樣程序還可以運(yùn)行。如果直接訪問別人的庫,主庫一修改,別的微服務(wù)程序馬上就會報錯。

向后兼容的數(shù)據(jù)庫更新:

從上面的論述可以看出,數(shù)據(jù)庫表結(jié)構(gòu)的修改是一個影響范圍很廣的事情。在微服務(wù)架構(gòu)中,共享的表在別的服務(wù)中也會有一個只讀的拷貝?,F(xiàn)在當(dāng)你要更改表結(jié)構(gòu)時,還需要考慮到對別的微服務(wù)的影響。當(dāng)在單體(Monolithic)架構(gòu)中,為了保證程序部署能夠回滾,數(shù)據(jù)庫的更新是向后兼容的。需要兼容性的另一個原因是支持藍(lán)綠發(fā)布(Blue-Green  Deployment)。在這種部署方式中,你同時擁有新舊版本的代碼,由負(fù)載均衡來決定每一個請求指向那個版本。它們可以共享一個數(shù)據(jù)庫(這就要求數(shù)據(jù)庫是向后兼容的),也可以使用不同的數(shù)據(jù)。數(shù)據(jù)庫的更新簡單來講有以下幾種類型:

  • 增加表或字段:如果字段可取空值,這個操作是向后兼容的。如果是非空值就要插入一個缺省值。

  • 刪除表或字段:可先暫時保留被刪除表或字段,經(jīng)過幾個版本之后再刪除。

  • 修改字段名:新增加一個字段,把數(shù)據(jù)從舊字段拷貝到新字段,用數(shù)據(jù)庫觸發(fā)器(或程序)同步舊字段和新字段(供過渡時期使用)。  然后再在幾個版本之后把原來的字段刪除。

  • 修改表名:如果數(shù)據(jù)庫支持可更新視圖,最簡單的辦法是先修改表的名字,然后創(chuàng)建一個可更新視圖指向原來的表。如果數(shù)據(jù)庫不支持可更新視圖,使用的方法與修改字段名相似,需要創(chuàng)建新的表并做數(shù)據(jù)同步。

  • 修改字段類型:與修改字段名幾乎相同,只是在拷貝數(shù)據(jù)時,需要做數(shù)據(jù)類型轉(zhuǎn)換。

向后兼容的數(shù)據(jù)庫更新的好處是,當(dāng)程序部署出現(xiàn)問題時,如需進(jìn)行回滾。只要回滾程序就行了,而不必回滾數(shù)據(jù)庫?;貪L時一般只回滾一個版本。凡是需要刪除的表或字段在本次部署時都不做修改,等到一個或幾個版本之后,確認(rèn)沒有問題了再刪除。它的另一個好處就是不會對其他微服務(wù)中的共享表產(chǎn)生立刻的直接影響。當(dāng)本微服務(wù)升級后,其他微服務(wù)可以評估這些數(shù)據(jù)庫更新帶來的影響再決定是否需要做相應(yīng)的程序或數(shù)據(jù)庫修改。

跨服務(wù)事物:

微服務(wù)的一個難點(diǎn)是如何實(shí)現(xiàn)跨服務(wù)的事物支持。兩階段提交(Two-Phase  Commit)已被證明性能上不能滿足需求,現(xiàn)在基本上沒有人用。被一致認(rèn)可的方法叫Saga。它的原理是為事物中的每個操作寫一個補(bǔ)償操作(Compensating  Transaction),然后在回滾階段挨個執(zhí)行每一個補(bǔ)償操作。示例如下圖,在一個事物中共有3個操作T1,T2,T3。每一個操作要定義一個補(bǔ)償操作,C1,C2,C3。事物執(zhí)行時是按照正向順序先執(zhí)行T1,當(dāng)回滾時是按照反向順序先執(zhí)行C3。  事物中的每一個操作(正向操作和補(bǔ)償操作)都被包裝成一個命令(Command),Saga執(zhí)行協(xié)調(diào)器(Saga Execution Coordinator  (SEC))負(fù)責(zé)執(zhí)行所有命令。在執(zhí)行之前,所有的命令都會按順序被存入日志中,然后Saga執(zhí)行協(xié)調(diào)器從日志中取出命令,依次執(zhí)行。當(dāng)某個執(zhí)行出現(xiàn)錯誤時,這個錯誤也被寫入日志,并且所有正在執(zhí)行的命令被停止,開始回滾操作。

微服務(wù)的數(shù)據(jù)庫設(shè)計是怎樣的

Saga放松了對一致性(Consistency)的要求,它能保證的是最終一致性(Eventual  Consistency),因此在事物執(zhí)行過程中數(shù)據(jù)是不一致的,并且這種不一致會被別的進(jìn)程看到。在生活中,大多數(shù)情況下,我們對一致性的要求并沒有那么高,短暫的不一致性是可以接收的。例如銀行的轉(zhuǎn)賬操作,它們在執(zhí)行過程中都不是在一個數(shù)據(jù)庫事物里執(zhí)行的,而是用記賬的方式分成兩個動作來執(zhí)行,保證的也是最終一致性。

Saga的原理看起來很簡單,但要想正確的實(shí)施還是有一定難度的。它的核心問題在于對錯誤的處理,要把它完全講明白需要另寫一遍文章,我現(xiàn)在只講一下要點(diǎn)。網(wǎng)絡(luò)環(huán)境是不可靠的,正在執(zhí)行的命令可能很長時間都沒有返回結(jié)果,這時,第一,你要設(shè)定一個超時。第二,因為你不知道沒有返回值的原因是,已經(jīng)完成了命令但網(wǎng)絡(luò)出了問題,還是沒完成就犧牲了,因此不知道是否要執(zhí)行補(bǔ)償操作。這時正確的做法是重試原命令,直到得到完成確認(rèn),然后再執(zhí)行補(bǔ)償操作。但這對命令有一個要求,那就是這個操作必須是冪等的(Idempotent),也就是說它可以執(zhí)行多次,但最終結(jié)果還是一樣的。

另外,有些操作的補(bǔ)償操作比較容易生成,例如付款操作,你只要把錢款退回就可以了。但有些操作,像發(fā)郵件,完成之后就沒有辦法回到之前的狀態(tài)了,這時就只能再發(fā)一個郵件更正以前的信息。因此補(bǔ)償操作不一定非要返回到原來的狀態(tài),而是抵消掉原來操作產(chǎn)生的效果。

微服務(wù)的拆分:

我們原來的程序大多數(shù)都是單體程序,但現(xiàn)在要把它拆分成微服務(wù),應(yīng)該怎樣做才能降低對現(xiàn)有應(yīng)用的影響呢?

微服務(wù)的數(shù)據(jù)庫設(shè)計是怎樣的

我們用上面的圖來做例子。它共有兩個程序,一個是“Styling app”,另一個是“Warehouse  app”,它們共享圖中下面的數(shù)據(jù)庫,庫里有三張表,“core client”,“core sku”,“core item”。

微服務(wù)的數(shù)據(jù)庫設(shè)計是怎樣的

假設(shè)我們要拆分出來一個微服務(wù)叫“client-service”,它需要訪問“core  client”表。第一步,我們先把程序從原來的代碼里拆分出來,變成一個服務(wù).  數(shù)據(jù)庫不動,這個服務(wù)仍然指向原來的數(shù)據(jù)庫。其他程序不再直接訪問這個服務(wù)管理的表,而是通過服務(wù)調(diào)用或另建共享表來獲取數(shù)據(jù)。

微服務(wù)的數(shù)據(jù)庫設(shè)計是怎樣的

第二步,再把服務(wù)的數(shù)據(jù)庫表拆分出來,這時微服務(wù)就擁有它自己的數(shù)據(jù)庫了,而不再需要原來的共享數(shù)據(jù)庫了。這時就成了一個真正意義上的的微服務(wù)。

上面只講了拆分一個微服務(wù),如果有多個需要拆分,則需一個一個按照上面講的方法依次進(jìn)行。

另外,Martin Fowler在他的文章"Break Monolith into  Microservices"里有一個很好的建議。那就是,當(dāng)你把服務(wù)從單體程序里拆分時,不要只想著把代碼拆分出來。因為現(xiàn)在的需求可能已經(jīng)跟原來有所不同,原先的設(shè)計可能也不太適用了。而且,技術(shù)也已更新,代碼也要作相應(yīng)的改造。更好的辦法是重寫原來的功能(而不是重寫原來的代碼),把重點(diǎn)放在拆分業(yè)務(wù)功能上,而不是拆分代碼上,用新的設(shè)計和技術(shù)來實(shí)現(xiàn)這個業(yè)務(wù)功能。

數(shù)據(jù)庫設(shè)計是微服務(wù)設(shè)計的一個關(guān)鍵點(diǎn),基本原則是每個微服務(wù)都有自己單獨(dú)的數(shù)據(jù)庫,而且只有微服務(wù)本身可以訪問這個數(shù)據(jù)庫。微服務(wù)之間的數(shù)據(jù)共享可以通過服務(wù)調(diào)用,或者主、從表的方式實(shí)現(xiàn)。在共享數(shù)據(jù)時,要找到合適的同步方式。在微服務(wù)架構(gòu)中,數(shù)據(jù)庫的修改影響廣泛,需要保證這種修改是向后兼容的。實(shí)現(xiàn)跨服務(wù)事物的標(biāo)準(zhǔn)方法是Saga。當(dāng)把單體程序拆分成微服務(wù)時,可以分步進(jìn)行,以減少對現(xiàn)有程序的影響。

關(guān)于微服務(wù)的數(shù)據(jù)庫設(shè)計是怎樣的就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI