2020年4月2日 星期四

微服務架構下的常見6種資料庫存取設計模式


微服務架構下的常見6種資料庫存取設計模式
「資料庫存取」在一個單體(monolithic)系統裡常因為系統規模逐漸擴大,表格逐漸增多,而變得愈來愈棘手:
1.      SQL在程式裡是字串不好追蹤也不好維護。
2.      查詢時連接(join)愈來愈多的表格,效能愈來愈差。
3.      交易時包含愈來愈多表格,效能不好,也容易出現死結(dead lock)
軟體的成敗常決定於資料管理,必須在正確時間提供正確數字給利益攸關的使用者;接下來分享微服務架構下的6種資料管理設計模式(pattern),讀者可以選擇適合自己專案的設計模式,模式間也會有互相結合的情況。

1.      服務擁有自己的資料庫(Database Per Service)設計模式
在這種模式下,每一個微服務都管理自己的資料庫。這也表示沒有其他微服務可以存取自己的資料庫,只能透過定義良好的微服務進行資料的通信或交換。
聽起來不難,但實際上要並不容易,因為通常商業邏輯必須依賴服務之間的資料來互相支援,這導致牽扯不清,像一棵大樹下的盤根錯節的樹根。
這個模式的成功取決於設計時商業邏輯邊界(context boundary)的定義;建構新專案或新服務比較簡單,重構龐大的舊單體系統則比較麻煩。其他常見的挑戰還包含跨服務的資料庫交易如何維持一致性等。
如果設計成功,好處是服務間的鬆耦合(loose coupling),因此可以讓服務重複使用,也可以將硬體資源如CPURAM等賦予真正需要的服務,甚至依據服務類別選擇資料庫種類。

2.      服務共享資料庫(Shared Database)設計模式
若前述「Database Per Service」有窒礙難性的地方,自然就只能採行「Shared Database」的設計模式。
這種模式的優點是使用方式對開發人員而言比較熟悉,等同於開發較小規模的單體式系統;對資料庫交易的ACID都與過去習慣做法一致,也相對保守、安全。缺點是比較用不到微服務的好處,多個微服務同時存取同一個資料庫,容易有資源競爭或資料鎖定的問題。
總體而言,這種方法弊大於利。

3.      API複合(API Composition)設計模式
這種模式常見於在微服務架構中「合併」多服務的查詢結果。
在這種模式下,API組件者(composer)會依照既定順序呼叫相關微服務,並在提供資料給使用者之前先在記憶體中串接(in-memory join)。缺點是相較於SQL join通常會取回多餘的資料,而且大型資料集合在記憶體中串接效率不彰因此影響效能。

4.      指令與查詢分離(Command Query Responsibility Segregation, CQRS)設計模式
對資料庫而言,寫入(write)與讀取(read)有很大的不同:
l  對系統的負載不同。
l  寫入比讀取要考慮的事務複雜,如交易一致性。
l  資訊安全考量也不同。
l  寫入時對象是「正規化」的資料表,讀取時卻經常是「反正規化」的資料,例如會將成用的查詢建立View物件。
微軟資料庫的快照(snapshot)解決方案就是基於COW (Copy On Write)的原則建置讀寫分離的架構。
















x

-資料庫的讀寫分離
CQRS也主張程式對資料庫的存取應該「讀寫分離」:
l   (write):執行後會改變物件狀態,在這裡使用「Command」描述。
l   (read):查看物件結果,而且不會改變物件的狀態、對物件本身沒有副作用,在這裡使用「Query」描述。
這個概念來自於物件導向的「命令與查詢分離(CQS, Command Query Separation)」,出自於1987Betrand MeyerObject-Oriented Software Construction(物件導向軟體建構)一書,其原始概念是我們可以把物件操作分為命令(Command)和查詢(Query)兩種形式。
CQRS可以看成解決「API複合」模式的問題的一種嘗試。因為在將資料寫入資料庫的同時,記憶體或其他地方中可以保留一份,查詢時就可以直接使用這份資料而不需要和經常被更新的資料競爭資源。概念為:
-服務層級的CQRS

5.      事件溯源(Event Sourcing)設計模式
這種模式經常和CQRS合併應用。負責寫入的微服務在改變資料狀態時將發布事件(event)並儲存資料於事件中,關聯的讀取微服務即可取得資料而不需要再查詢資料庫。這也是觀察者(Observer)設計模式的實現。
必須注意的是,這種模式必須確認只有預期的寫入微服務可以異動資料,否則將造成讀取服務取得的資料不一致。
這種模式的缺點是讀、寫服務需要的資料內容通常不同,因此服務寫入資料庫時保留的資料不見得直接適用於讀取服務,通常還需要整理。

6.      SAGA設計模式
SAGA模式用來解決跨服務的交易一致性需求。
SAGA本質上代表一連串的微服務區域(local)交易。在SAGA內進行交易的服務會發布交易事件,每一個微服務只在收到前一個服務的事件通知後才進行自己的交易內容;若有交易內容失敗SAGA會發動rollback以回復到交易前狀態,若全部成功則commit
舉一個送餐應用程序為例。當客戶嘗試訂購食物時,可能會發生以下步驟:
l  「訂單微服務」建立訂單物件。此時訂單處於「暫停(PENDING)」狀態,SAGA將管理後續一連串的事件。
l  SAGA藉由「餐廳微服務」聯絡被挑選的餐廳,餐廳藉由「餐廳微服務」回應是否接單。
l  SAGA取得「餐廳微服務」的回應,依據內容決定訂單物件狀態為「受理(APPROVED)」或「拒絕(REJECTED)」,並藉由「訂單微服務」回應客戶訂單明細或抱歉訊息。
如本例,當以微服務串接流程時會比一般點對點(point-to-point)的程式呼叫來的複雜,而SAGA就扮演居中協調的角色。

在接下來的文章中,我們將更進一步探討這些模式以及實現方式。

沒有留言:

張貼留言