微服務架構的數據設計模式

最近參與公司項目研發,在其中發現對于數據的管理存在一些小問題,根據以往經驗,在這里記錄下微服務數據設計模式。
微服務架構中的服務是松耦合的,可以獨立開發、部署和擴展。每個微服務都需要不同類型的數據和存儲方式,也因為這樣每個微服務都有自己的數據庫。
一、每個服務的數據庫
每個微服務都有自己的數據庫,可以自由選擇如何管理數據。
1、每個服務都有一個數據庫的好處
- 松耦合,各自服務可以更加專注自己的專業領域
- 自由選擇數據庫類型,如 MySQL 等 RDBMS、Cassandra 等寬列數據庫、MongoDB 等文檔數據庫、Redis 等鍵值存儲和 Neo4J 等圖形數據庫。
是否需要為每個服務使用不同的數據庫服務器?這不是一個硬性要求。讓我們看看我們能做些什么。
2、如果您使用的是 RDMS,那么就包括以下特性:
- 專用表—每個服務擁有一組表,只能由該服務訪問。
- 專用數據庫架構—每個服務都有一個私有的數據庫架構。
- 專用數據庫服務器—每個服務都有自己的數據庫服務器。
3、每個服務都有一個數據庫的挑戰
需要連接多個數據庫的查詢?—以下數據模式可以克服這一挑戰。
- 事件溯源
- API 組成
- 命令查詢職責分離 (CQRS)
跨多個數據庫事務?—為了解決這個問題,我們可以使用Saga 模式。
二、事件溯源
通過事件溯源,業務實體的狀態由一系列狀態變化的事件跟蹤。每當業務實體的狀態發生變化時,都會將新事件添加到事件列表中。由于保存事件是一個單一的操作,它本質上是原子的。通過重放事件,應用程序重建實體的當前狀態。
應用程序將事件保存在事件存儲中,事件存儲是事件數據庫。可以使用其 API 從存儲中添加和檢索事件。事件存儲也充當消息代理。服務可以通過其 API 訂閱事件。當服務在事件存儲中保存一個事件時,它會發送給所有感興趣的訂閱者。當實體有大量事件時,應用程序可以定期保存實體當前狀態的快照以優化加載。應用程序查找最近的快照以及自該快照以來發生的事件以重建當前狀態。這減少了要重播的事件的數量。

1、事件溯源的好處
- 使用它解決了事件驅動架構的關鍵挑戰之一,并使得在狀態變化時可靠地發布事件。
- 避免了對象關系阻抗不匹配問題,持久化事件而不是域對象。
- 對實體提供 100% 可靠的審計日志。
- 允許執行確定實體在任何時間點的狀態的時間查詢。
- 基于事件溯源的業務邏輯涉及交換事件的松散耦合實體。使從單體應用程序遷移到微服務架構變得容易得多。
2、事件溯源的缺點
- 有一定學習成本,目前還是一種不太成熟的技術。
- 查詢事件存儲很困難,需要一個典型的查詢來重建實體狀態。可能會導致低效和復雜的查詢。因此,應用程序必須使用命令查詢職責分離 (CQRS) 來實現查詢。反過來,這意味著應用程序必須處理最終一致的數據。
三、API 組成
您可以使用 API 組合模式實現從多個服務中檢索數據的查詢操作。在這個模式中,通過調用擁有數據的服務然后組合結果來實現查詢操作。

1、API 組合的好處
在微服務架構中查詢數據的一種便捷方式。
2、API組合的缺點
有時,查詢會導致大型數據集的低效內存連接。
四、命令查詢職責分離 (CQRS)
RDBMS 通常用作記錄事務系統和文本搜索數據庫,例如用于文本搜索查詢的 Elasticsearch 或 Solr。一些應用程序通過同時寫入兩者來保持數據庫同步。其他人定期將數據從 RDBMS 復制到文本搜索引擎。基于此架構構建的應用程序利用了多個數據庫的優勢、RDBMS 的事務屬性以及文本數據庫的查詢能力。CQRS 概括了這種架構。
微服務架構在實現查詢時面臨三個常見挑戰。
- 使用 API 組合模式檢索分散在多個服務中的數據,從而導致成本高昂且效率低下的內存連接。
- 數據以不能有效支持擁有數據的服務所需查詢的格式或數據庫中存儲。
- 分離關注點意味著擁有數據的服務不應該負責實現查詢操作。
這三個問題都可以通過使用 CQRS 模式來解決。
CQRS 的主要目標是分離或分離關注點。因此,持久數據模型分為兩部分:命令端和查詢端。
創建、更新和刪除操作由命令端模塊和數據模型實現。查詢由查詢端模塊和數據模型實現。通過訂閱命令行發布的事件,查詢端保持其數據模型與命令端同步

1、CQRS 的好處
- 實現高效查詢實現—如果您使用 API 組合模式來實現查詢,您可能會遇到大型數據集的高成本、低效的內存連接。對于這些查詢,使用預先來自連接兩個或更多服務數據的CQRS 視圖更有效。
- 能夠有效實現多種查詢—通常很難使用單一持久數據模型來支持所有查詢。在CQRS 中,定義一個或多個視圖有效地實現特定查詢,消除了單個數據存儲的限制。
- 實現基于事件溯源的應用程序中查詢—CQRS 還克服了事件溯源的一個重要限制。事件存儲僅支持基于主鍵的查詢。CQRS 模式通過定義一個或多個聚合視圖來解決此限制,這些視圖通過訂閱由事件源聚合發布的事件流來保持最新。
- 關注點分離改進—域模型和持久數據模型不支持命令和查詢。CQRS 將服務的命令和查詢端分離為單獨的代碼模塊和數據庫模式。
2、CQRS 的缺點
- 更復雜的架構—為了更新和查詢視圖,開發者需要編寫查詢端服務。應用程序可能使用不同類型的數據庫,這增加了開發人員和 DevOps 的復雜性。
- 處理復制延遲—在從命令端發布事件到由查詢端處理事件以及更新視圖之間存在延遲。
五、Saga模式
使用 sagas,您可以在不使用分布式事務的情況下保持微服務架構中數據的一致性。您為跨多個服務更新數據的每個命令定義一個 saga。saga 是一系列本地事務。本地事務使用ACID事務框架更新單個服務中的數據。
Sagas 利用補償事務來回滾更改。假設saga的第n個交易失敗。必須撤消前 (n-1) 個事務。結果,總共 (n-1) 個補償事務將被啟動以以相反的順序回滾更改。
1、Saga協調
為了實現一個 saga,它需要邏輯來協調其步驟。一旦系統命令啟動了一個 saga,協調邏輯必須選擇并指示第一個 saga 執行本地事務。一旦該事務完成,編排協調就會選擇并調用下一個 saga 參與者。這個過程一直持續到傳奇完成。如果本地事務失敗,saga 必須以相反的順序執行補償事務。
2、有幾種方法可以構建 saga 的協調邏輯:
編排?:在saga的參與者之間分配決策和排序。他們主要通過交換事件進行通信。

(1)基于編排的saga優勢
- 簡單性—當創建、更新或刪除業務對象時,服務會發布事件。
- 簡單依賴關系—不引入循環依賴關系。
- 松耦合—服務實現由編排器調用的 API,因此它不需要知道 saga 參與者發布的事件。
- 簡化業務邏輯—在 saga 編排器中,saga 協調邏輯是本地化的。領域對象不知道它們所涉及的 sagas。
(2)基于編排的缺點
- 更難理解—編排將 saga 的實現分布在服務之間,每個服務都是獨立的這就需要每個管理對每個服務都需要了解。
- 服務之間的循環依賴—saga 參與者訂閱彼此的事件,這通常會產生循環依賴。
- 緊密耦合的風險—saga的參與者必須訂閱所有影響他們的事件。
編排?—一個 saga 的協調邏輯應該集中在一個 saga 編排器類中。在 saga 期間,編排器向參與者發送命令消息,告訴他們應該執行哪些操作。


































