微服務的資料庫設計

2021-09-28 19:22:06 字數 4146 閱讀 3887

微服務設計的乙個關鍵是

資料庫設計,基本原則是每個服務都有自己單獨的資料庫,而且只有微服務本身可以訪問這個資料庫。它是基於下面三個原因。

理想的設計是你的資料庫只有你的服務能訪問,你也只呼叫自己資料庫中的資料,所有對別的微服務的訪問都通過服務呼叫來實現(請參閱「微服務之間呼叫的最佳設計「)。當然,在實際應用中,單純的服務呼叫可能不能滿足效能或其他要求,不同的微服務都多少需要共享一些資料。

微服務之間的資料共享可以有下四種方式。

靜態表:

有一些靜態的資料庫表,例如國家,可能會被很多程式用到,而且程式內部需要對國家這個表做連線(join)生成終端使用者展示資料,這樣用微服務呼叫的方式就效率不高,影響效能。乙個辦法是在每個微服務中配置乙個這樣的表,它是唯讀的,這樣就可以做資料庫連線了。當然你需要保證資料同步。這個方案在多數情況下都是可以接受的,因為以下兩點:

靜態的資料庫表結構基本不變:因為一旦表結構變了,你不但要更改所有微服務的資料庫表,還要修改所有微服務的程式。

資料庫表中的資料變化不頻繁:這樣資料同步的工作量不大。另外當你同步資料庫時總會有延遲,如果資料變化不頻繁那麼你有很多同步方式可供選擇。

唯讀業務資料訪問:

如果你需要讀取別的資料庫裡的動態業務資料, 理想的方式是服務呼叫。如果你只是呼叫其他微服務做一些計算,一般情況下效能都是可以接受的。如果你需要做資料的連線,那麼你可以用程式**來做,而不是用sql語句。如果測試之後效能不能滿足要求,那你可以考慮在自己的資料庫裡建一套唯讀資料表。資料同步方式大致有兩種。如果是事件驅動方式,就用發訊息的方式進行同步,如果是rpc方式,就用資料庫本身提供的同步方式或者第三方同步軟體。

通常情況下,你可能只需要其他資料庫的幾張表,每張表只需要幾個字段。這時,其他資料庫是資料的最終**,控制所有寫操作以及相應的業務驗證邏輯,我們叫它主表。你的唯讀庫可以叫從表。 當一條資料寫入主表後,會發一條廣播訊息,所有擁有從表的微服務監聽訊息並更新唯讀表中的資料。但這時你要特別小心,因為它的危險性要比靜態表大得多。第一它的表結構變更會更頻繁,而且它的變更完全不受你控制。第二業務資料不像靜態表,它是經常更新的,這樣對資料同步的要求就比較高。要根據具體的業務需求來決定多大的延遲是可以接受的。

另外它還有兩個問題:

資料的容量:資料庫中的資料量是影響效能的主要因素。因為這個資料是外來的,不利於掌握它的流量規律,很難進行容量規劃,也不能更好地進行效能調優。

** 介面外洩**:微服務之間的介面本來只有服務呼叫介面,這時你可以對內部程式和資料庫做任何更改,而不影響其他服務。現在資料庫表結構也變成了介面的一部分。介面一旦發布之後,基本是不能更改的,這大大限制了你的靈活性。幸運的是因為另外建了一套表,有了乙個緩衝,當主表修改時,從表也許不需要同步更新。

除非你能用服務呼叫(沒有本地唯讀資料庫)的方式完成所有功能,不然不管你是用rpc方式還是事件驅動方式進行微服務整合,上面提到的問題都是不可避免的。但是你可以通過合理規劃資料庫更改,來減少上面問題帶來的影響,下面將會詳細講解。

讀寫業務資料訪問:

這是最複雜的一種情況。一般情況下,你有乙個表是主表,而其他表是從表。主表包含主要資訊,而且這些主要資訊被複製到從表,但微服務會有額外字段需要寫入從表。這樣本地微服務對從表就既有讀也有寫的操作。而且主表和從表有乙個先後次序的關係。從表的主鍵**於主表,因此一定先有主表,再有從表。**

直接訪問其它資料庫:從上面的論述可以看出,資料庫表結構的修改是乙個影響範圍很廣的事情。在微服務架構中,共享的表在別的服務中也會有乙個唯讀的拷貝。現在當你要更改表結構時,還需要考慮到對別的微服務的影響。當在單體(monolithic)架構中,為了保證程式部署能夠回滾,資料庫的更新是向後相容的。需要相容性的另乙個原因是支援藍綠發布(blue-green deployment)。在這種部署方式中,你同時擁有新舊版本的**,由負載均衡來決定每乙個請求指向那個版本。它們可以共享乙個資料庫(這就要求資料庫是向後相容的),也可以使用不同的資料。資料庫的更新簡單來講有以下幾種型別:

向後相容的資料庫更新的好處是,當程式部署出現問題時,如需進行回滾。只要回滾程式就行了,而不必回滾資料庫。回滾時一般只回滾乙個版本。凡是需要刪除的表或字段在本次部署時都不做修改,等到乙個或幾個版本之後,確認沒有問題了再刪除。它的另乙個好處就是不會對其他微服務中的共享表產生立刻的直接影響。當本微服務公升級後,其他微服務可以評估這些資料庫更新帶來的影響再決定是否需要做相應的程式或資料庫修改。

微服務的乙個難點是如何實現跨服務的事物支援。兩階段提交(two-phase commit)已被證明效能上不能滿足需求,現在基本上沒有人用。被一致認可的方法叫saga。它的原理是為事物中的每個操作寫乙個補償操作(compensating transaction),然後在回滾階段挨個執行每乙個補償操作。示例如下圖,在乙個事物中共有3個操作t1,t2,t3。每乙個操作要定義乙個補償操作,c1,c2,c3。事物執行時是按照正向順序先執行t1,當回滾時是按照反向順序先執行c3。 事物中的每乙個操作(正向操作和補償操作)都被包裝成乙個命令(command),saga執行協調器(saga execution coordinator (sec))負責執行所有命令。在執行之前,所有的命令都會按順序被存入日誌中,然後saga執行協調器從日誌中取出命令,依次執行。當某個執行出現錯誤時,這個錯誤也被寫入日誌,並且所有正在執行的命令被停止,開始回滾操作。**

saga放鬆了對一致性(consistency)的要求,它能保證的是最終一致性(eventual consistency),因此在事物執行過程中資料是不一致的,並且這種不一致會被別的程序看到。在生活中,大多數情況下,我們對一致性的要求並沒有那麼高,短暫的不一致性是可以接收的。例如銀行的轉賬操作,它們在執行過程中都不是在乙個資料庫事物裡執行的,而是用記賬的方式分成兩個動作來執行,保證的也是最終一致性。

saga的原理看起來很簡單,但要想正確的實施還是有一定難度的。它的核心問題在於對錯誤的處理,要把它完全講明白需要另寫一遍文章,我現在只講一下要點。網路環境是不可靠的,正在執行的命令可能很長時間都沒有返回結果,這時,第一,你要設定乙個超時。第二,因為你不知道沒有返回值的原因是,已經完成了命令但網路出了問題,還是沒完成就犧牲了,因此不知道是否要執行補償操作。這時正確的做法是重試原命令,直到得到完成確認,然後再執行補償操作。但這對命令有乙個要求,那就是這個操作必須是冪等的(idempotent),也就是說它可以執行多次,但最終結果還是一樣的。

我們原來的程式大多數都是單體程式,但現在要把它拆分成微服務,應該怎樣做才能降低對現有應用的影響呢?**

** 假設我們要拆分出來乙個微服務叫「client-service」,它需要訪問「core client」表。第一步,我們先把程式從原來的**裡拆分出來,變成乙個服務. 資料庫不動,這個服務仍然指向原來的資料庫。其他程式不再直接訪問這個服務管理的表,而是通過服務呼叫或另建共享表來獲取資料。**

第二步,再把服務的資料庫表拆分出來,這時微服務就擁有它自己的資料庫了,而不再需要原來的共享資料庫了。這時就成了乙個真正意義上的的微服務。

上面只講了拆分乙個微服務,如果有多個需要拆分,則需乙個乙個按照上面講的方法依次進行。

另外,martin fowler在他的文章"break monolith into microservices"裡有乙個很好的建議。那就是,當你把服務從單體程式裡拆分時,不要只想著把**拆分出來。因為現在的需求可能已經跟原來有所不同,原先的設計可能也不太適用了。而且,技術也已更新,**也要作相應的改造。更好的辦法是重寫原來的功能(而不是重寫原來的**),把重點放在拆分業務功能上,而不是拆分**上,用新的設計和技術來實現這個業務功能。

資料庫設計是微服務設計的乙個關鍵點,基本原則是每個微服務都有自己單獨的資料庫,而且只有微服務本身可以訪問這個資料庫。微服務之間的資料共享可以通過服務呼叫,或者主、從表的方式實現。在共享資料時,要找到合適的同步方式。在微服務架構中,資料庫的修改影響廣泛,需要保證這種修改是向後相容的。實現跨服務事物的標準方法是saga。當把單體程式拆分成微服務時,可以分步進行,以減少對現有程式的影響。

微服務之間呼叫的最佳設計

update your database schema without downtime

evolutionary database design

fault-tolerance and data consistency using distributed sagas

distributed sagas: a protocol for coordinating microservices - caitie mccaffrey - jotb17

managing data in microservices

how to break a monolith into microservices

微服務化的資料庫設計與讀寫分離

劉超,畢業於上海交通大學,15年雲計算領域研發及架構經驗,先後在emc,cctv 資訊頻道,hp,華為,網易從事雲計算和大資料架構工作 在工作中積累了大量運營商系統,網際網路金融系統,電商系統等容器化和微服務化經驗。用於管理使用者的連線,並會做一定的認證和鑑權。這個模組就是來接受使用者的sql語句的...

微服務搭建資料庫系統

資料訪問層是微服務系統中比較重要的一環,怎樣通過 springboot 搭建資料庫環境,單資料來源與多資料來源的比較與實現方式,以及怎樣結合 mybatis 不僅能夠實現自動實現資料庫表與實體類 dao 層的自動生成,還能夠實現動態資料來源訪問等。多資料來源中常用到的核心技術。那麼,通過本場 cha...

微服務系統設計篇 二 如何做資料庫選型

在微服務設計中,資料庫的選型是不可缺少的一環,後台的核心是與資料打交道,在不同的業務場景選擇的資料庫不一樣,好的資料庫選型能夠解決業務的效能瓶頸,如果資料庫選擇不恰當,會使得服務的效能上不去,因此我們需要對一些常用的資料庫有一些了解,這樣才能因地制宜,發揮系統最好的效能。常見的資料庫分類 資料庫型別...