目錄
- 前言
- 1. 使用API組合模式進行查詢
- 1.1 findOrder()查詢操作
- 1.2 什么是API組合模式
- 1.3 使用API組合模式實作findOrder()查詢操作
- 1.4 設計問題一:由誰來擔任API組合器的角色
- 1.5 設計問題二:如何撰寫有效的聚合邏輯
- 1.6 API組合模式的好處與弊端
- 2. 使用CQRS模式
- 2.1 為什么要使用CQRS
- 2.2 CQRS隔離命令與查詢
- 2.3 CQRS和查詢專用服務
- 2.4 CQRS的好處與弊端
- 3. 設計CQRS視圖
- 3.1 選擇視圖存盤庫
- 3.2 設計資料訪問模塊
- 3.3 添加和更新CQRS視圖
- 4. 實作基于AWS DynamoDB的CQRS視圖
- 4.1 OrderHistoryService的設計
- 4.2 OrderHistoryEventHandlers模塊
- 5. 本章小結
- 最后
前言
在微服務架構中撰寫查詢具有挑戰性,查詢通常需要檢索分散在多個服務所擁有的資料庫中的資料,使用傳統的分布式查詢處理機制雖然在技術上可行,但會打破服務之間的隔離與封裝;
在微服務架構中實作查詢操作有兩種不同的模式:
- API組合模式:這是最簡單的方法,應盡可能使用,它的作業原理是讓擁有資料的服務的客戶端負責呼叫服務,并組合服務回傳的查詢結果;
- 命令查詢職責隔離(CQRS)模式:它比API組合模式更強大,但也更復雜,它維護一個或多個視圖資料庫,其唯一的目的是支持查詢;
這是一本關于微服務架構設計方面的書,這是本人閱讀的學習筆記,下面對一些符號做些說明:
()為補充,一般是書本里的內容;
[]符號為筆者筆注;
1. 使用API組合模式進行查詢
1.1 findOrder()查詢操作
findOrder()查詢操作是從多個服務獲取資料的查詢方法;

圖解:基于微服務架構的FTGO應用程式版本中,資料分散在以下服務中;
- Order Service:基本訂單資訊,包括詳細資訊和狀態;
- Kitchen Service:從餐館的角度看訂單的狀態以及預計取餐時間;
- Delivery Service:訂單的交付狀態、預計送餐時間及送餐員的當前位置;
- Accounting Service:訂單的付款狀態;
1.2 什么是API組合模式

圖解:
- API組合模式:通過查詢每個服務的API并組合結果,實作從多個服務檢索資料的查詢;
- 其有兩種型別的參與者:
- API組合器:它通過查詢資料提供方的服務來實作查詢操作;
- 資料提供方服務:擁有查詢回傳的部分資料的服務;
- 是否可以使用此模式實作特定查詢操作取決于幾個因素,包括資料的磁區方式、擁有資料的服務公開的API的功能,以及服務使用資料庫的功能;
1.3 使用API組合模式實作findOrder()查詢操作

圖解:
- 四個提供方服務實作一個REST介面,該介面回傳對應于單個聚合的回應;
1.4 設計問題一:由誰來擔任API組合器的角色
由服務的客戶端:
- 缺點:對于防火墻之外的客戶以及通過較慢網路訪問的服務,此選擇不可用(詳情查看第八章);

由實作應用程式外部API的API Gateway:
- 可以使得在防火墻外運行的客戶端能夠通過單個API呼叫有效地從眾多服務中檢索資料;

將API組合器實作為獨立的服務
- 在外部訪問查詢時,由于其聚合邏輯過于復雜,因此無法在API Gateway中完成查詢,必須使用單獨的服務;

1.5 設計問題二:如何撰寫有效的聚合邏輯
- 應該使用回應式編程模型;
- 有時API聚合器需要一個提供方服務的結果才能呼叫另一個服務;在這種情況下,它需要按順序呼叫一部分提供方服務;
- 應該使用基于Java CompletableFuture、RxJava可觀測或其他類似的回應式設計(詳情見《第8章 API Gateway模式》);
1.6 API組合模式的好處與弊端
好處:
- 實作查詢操作簡單直觀;
弊端:
- 增加了額外的開銷:涉及多個請求和資料庫查詢,需要更多的計算和網路資源;
- 帶來可用性降低的風險:操作的可用性隨著所涉及的服務數量而下降;
- 解決辦法:在提供方不可用時,回傳先前快取的資料;或者讓API組合器回傳不完整的資料;
- 缺乏事務資料一致性;
2. 使用CQRS模式
2.1 為什么要使用CQRS
- 涉及多個服務的查詢,API組合模式無法有效實作;
- 因為并非所有服務都存盤用于過濾或排序的屬性,如Order Service和Kitchen Service兩項服務存盤了Order的選單項,而Delivery Service和Accounting Service都不存盤選單項;
- 解決辦法:讓API組合器進行記憶體中連接;讓API組合器從Order Service和Kitchen Service檢索匹配的訂單,然后通過ID從其他服務請求訂單;
- CQRS可以解決服務的資料庫(資料模型)不能有效查詢的問題;
- 如:在進行地理空間查詢時會生成資料副本,CQRS解決了同步副本問題;
- CQRS考慮隔離問題的必要性,避免過多的職責導致過載服務;
2.2 CQRS隔離命令與查詢

圖解:
- 位于命令端的領域模型處理CRUD操作并映射到其自己的資料庫;
- 命令端在資料發生變化時發布領域事件;
2.3 CQRS和查詢專用服務

圖解:
- 查詢服務的API只包含查詢操作,并無命令操作;
- 它通過訂閱一個或多個其他服務發布的事件來確保它的資料庫是不斷更新的,并由此實作查詢操作;
- 查詢端服務訂閱由多個服務發布的事件;
2.4 CQRS的好處與弊端
好處:
- 在微服務架構中高效地實作查詢;
- 高效地實作多種不同的查詢型別;
- 在基于事件溯源技術的應用程式中實作查詢;
- 更進一步地實作問題隔離;
弊端:
- 更加復雜的架構:開發人員必須撰寫更新和查詢視圖的查詢端服務;
- 處理資料復制導致的延遲;
- 即:更新聚合后查詢聚合會看到聚合的先前版本;
- 解決方案:采用命令端和查詢端API為客戶端提供版本資訊,使其能夠判斷查詢端是否過時;
3. 設計CQRS視圖
CQRS視圖模塊包括由一個或多個查詢操作組成的API;

3.1 選擇視圖存盤庫
NoSQL:
- CQRS視圖受益于NoSQL資料庫更豐富的資料模型和性能,不受NoSQL資料庫事務處理能力的限制;
SQL資料庫:
- 在主流硬體上運行的現代關系型資料庫具有出色的性能;
- SQL資料庫通常具有非關系特征的擴展,如地理空間資料型別和查詢;
- CQRS視圖可能需要使用SQL資料庫才能支持報表引擎;
支持更新操作:
- 通常使用其主鍵更新或洗掉視圖資料庫中的記錄;
- 有時需要使用類似外鍵的做法來更新或洗掉記錄;

3.2 設計資料訪問模塊
事件處理程式和查詢API模塊不直接訪問資料庫存盤區,相反,它們使用資料訪問模塊,該模塊由資料訪問物件(DAO)及其輔助類組成;
- 處理并發更新確保更新冪等;
- 當視圖訂閱由多個聚合型別發布的事件時,多個事件處理程式可能同時更新同一記錄;
- 冪等事件處理程式:
- 為了確保可靠,事件處理程式必須記錄事件ID并以原子化的方式更新資料存盤區,如何試下取決于資料庫型別;
- 事件處理程式不需要記錄每個事件的ID,每個記錄僅需要存盤從給定聚合實體接收的max(eventId);
- 讓客戶端應用程式采用最終一致性的視圖:
- 執行更新命令后執行查詢命令可能看到的是更新前的資料 [有延遲],客戶端可以使用以下方法檢測這種不一致性:
- 命令端操作將包含已發布事件和ID標記回傳給客戶端,然后,客戶端將事件有關的ID傳遞給查詢操作,如果該事件尚未更新視圖,則回傳查詢錯誤;
- 視圖模塊可以使用重復事件檢測機制來實作這樣的功能;
3.3 添加和更新CQRS視圖
- 添加和更新CQRS視圖在概念上很簡單,即:
- 創建新視圖:開發查詢端模塊、設定資料存盤區并部署服務,查詢端模塊的事件處理程式處理所有事件,最終視圖將是最新的;
- 更新現有視圖:更改事件處理程式并從頭開始重構視圖;
- 但在實際中會產生一些問題,如下:
- 訊息代理無法無限期存盤資訊;
- 如:RabbitMQ會在消費者處理完訊息后洗掉該訊息;Apache Kafka可在配置的保留期內保留訊息,但也不會無限期存盤事件;
- 解決辦法:使用歸檔事件構建CQRS視圖,使用可擴展的大資料技術(如Apache Spark)實作;
- 處理所有事件所需的時間和資源隨時間推移而不斷增長;
- 解決辦法:增量式構建CQRS視圖,使用兩步增量演算法,第一步基于先前的快照和自創建快照以來發生的事件,定期計算每個聚合實體的快照;第二步使用快照和任何后續事件創建視圖;
4. 實作基于AWS DynamoDB的CQRS視圖
介紹如何使用DynamoDB為findOrderHistory()操作實作CQRS視圖;
4.1 OrderHistoryService的設計

圖解:
- OrderHistoryEventHandlers:訂閱各種服務發布的事件并呼叫OrderHistoryDAO;
- OrderHistoryQueryAPI模塊:實作REST API介面;
- OrderHistoryDataAccess:包含OrderHistoryDAO,它定義了更新和查詢ftgo-order-history DynamoDB表及其輔助類的方法;
- ftgo-order-history DynamoDB表:存盤訂單的DynamoDB表;
4.2 OrderHistoryEventHandlers模塊
此模塊由接收事件和更新DynamoDB表的事件處理程式組成;


圖解:
- 每個事件處理程式都有一個DomainEventEnvelope型別的引數,其中包含事件和描述事件的一些元資料;
5. 本章小結
- 實作從多個服務檢索資料的查詢具有挑戰性,因為每個服務的資料都是私有的;
- 有兩種方法可以實作這些型別的查詢:API組合模式和命令查詢職責隔離(CQRS)模式;
- 從多個服務獲取資料的API組合模式是實作查詢的最簡單方法,應盡可能使用;
- API組合模式的局限性是某些復雜查詢需要大型資料集的低效記憶體連接;
- 使用視圖資料庫實作查詢的CQRS模式功能更強大,但實作起來更復雜;
- CQRS視圖模塊必須處理并發更新以及檢測和丟棄重復事件;
- CQRS有助于改善問題隔離,服務不必為自己擁有的資料實作查詢功能;
- 客戶必須處理CQRS視圖的最終一致性;
最后

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/298285.html
標籤:其他
