如我們在本書中所見,雲端原生方法會變更您設計、部署和管理應用程式的方式。 它也會變更您管理和儲存數據的方式。
圖 5-1 對比顯示差異。
圖 5-1。 雲端原生應用程式中的數據管理
經驗豐富的開發人員可以輕鬆地辨識圖 5-1 左側的架構。 在此 整合型應用程式中,商務服務元件會共置在共用服務層中,從單一關係資料庫共享數據。
在許多方面,單一資料庫會讓數據管理保持簡單。 跨多個數據表查詢數據很簡單。 資料改變時,要麼一起更新,要麼全部復原。 ACID 交易 保證強強且即時一致性。
在雲端原生設計中,我們採取了不同的方法。 在圖 5-1 右側,請注意商務功能如何隔離成小型獨立 微服務。 每個微服務都會封裝特定的商務功能及其本身的數據。 整合型資料庫會分解成具有許多較小資料庫的分散式數據模型,每個資料庫都與微服務一致。 當煙霧散去時,我們會設計出每個微服務專用的資料庫。
為何每個微服務都需要獨立的資料庫?
每個微服務的這個資料庫提供許多優點,特別是對於必須快速發展並支援大規模規模的系統。 使用此模型...
- 網域數據會封裝在服務內
- 數據架構可以發展,而不會直接影響其他服務
- 每個數據存放區都可以獨立調整
- 一個服務中的數據存放區失敗不會直接影響其他服務
隔離數據也可讓每個微服務實作最適合其工作負載、記憶體需求和讀取/寫入模式的數據存放區類型。 選擇包括關係型、文件、索引鍵/值,甚至是圖形型數據存儲。
圖 5-2 呈現了雲端原生系統中多語言持久性的原理。
圖 5-2。 多語言資料持久性
請注意,上圖說明每個微服務如何支援不同類型的數據存放區。
- 產品目錄微服務會取用關係資料庫,以容納其基礎數據的豐富關係結構。
- 購物車微服務會取用分散式快取,以支持其簡單的索引鍵/值數據存放區。
- 排序微服務會同時使用 NoSql 檔資料庫來進行寫入作業,以及高度反正規化的索引鍵/值存放區,以容納大量讀取作業。
雖然關係資料庫仍與具有複雜數據的微服務相關,但 NoSQL 資料庫已相當受歡迎。 它們提供大規模擴展能力和高可用性。 其無架構本質可讓開發人員遠離具型別數據類別和 ORM 的架構,讓變更成本昂貴且耗時。 本章稍後我們將討論 NoSQL 資料庫。
雖然將數據封裝到個別的微服務可以提升靈活度、效能和延展性,但它也帶來了許多挑戰。 在下一節中,我們會討論這些挑戰,以及模式和做法,以協助克服這些挑戰。
跨服務查詢
雖然微服務是獨立的,且著重於特定功能功能,例如清查、出貨或訂購,但它們通常需要與其他微服務整合。 整合通常涉及一個微服務向另一個微服務查詢以取得數據。 圖 5-3 顯示案例。
圖 5-3。 跨微服務查詢
在上圖中,我們看到一個購物籃微服務可以將商品新增到使用者的購物籃中。 雖然此微服務的數據存放區包含購物籃和明細項目數據,但不會維護產品或定價數據。 相反地,這些數據項是由目錄和定價微服務所擁有。 這一方面有問題。 購物籃微服務如何在其資料庫中沒有產品或定價數據時,將產品新增至使用者的購物籃?
第 4 章中討論的其中一個選項是從購物籃到目錄和定價微服務的 直接 HTTP 呼叫 。 不過,在第 4 章中,我們說同步 HTTP 呼叫 會將微服務結合 在一起,減少其自主權,並降低其架構優點。
我們也可以使用每個服務的個別輸入和輸出佇列來實作 要求-回復模式 。 不過,此模式很複雜,而且需要管道來使要求和回應訊息相互關聯。 雖然它確實將後端微服務呼叫分離,但呼叫服務仍必須同步等候呼叫完成。 網路壅塞、暫時性錯誤或多載微服務,可能會導致長時間執行甚至失敗的作業。
相反地,移除跨服務相依性的廣泛接受模式是 具體化檢視模式,如圖 5-4 所示。
圖 5-4。 物化視圖模式
使用此模式時,您會在購物籃服務中放置本機數據表(稱為 讀取模型)。 下表包含產品與定價微服務所需的數據反正規化複本。 將數據直接複製到購物籃微服務,就不需要昂貴的跨服務呼叫。 透過服務的本地數據,您可以改善服務的回應時間和可靠性。 此外,有自己的數據復本可讓購物籃服務更具彈性。 假如目錄服務暫時無法使用,不會直接影響購物籃服務。 購物籃可以繼續運作,並使用來自自有商店的數據。
使用此方法的缺點是,您現在系統中有重複的資料。 不過, 在雲端原生系統中以策略方式 複製數據是既定的做法,而不是被視為反模式或不良做法。 請記住, 一個和只有一個服務 可以擁有數據集,並擁有該數據集的授權。 當記錄系統更新時,您需要同步讀取模型。 同步處理通常是透過具有 發行/訂閱模式的異步傳訊來實作,如圖 5.4 所示。
分散式交易
雖然跨微服務查詢數據很困難,但跨數個微服務實作交易會更加複雜。 無法低估在不同微服務中跨獨立數據源維護數據一致性的固有挑戰。 雲端原生應用程式中缺乏分散式交易表示您必須以程序設計方式管理分散式交易。 您會從 立即一致性 的世界移至 最終一致性的世界。
圖 5-5 顯示問題。
圖 5-5。 跨微服務實作交易
在上圖中,有五個獨立微服務參與建立訂單的分散式交易。 每個微服務都會維護自己的資料存儲,並為其存儲實作本地交易。 若要建立順序, 每個 個別微服務的本機交易都必須成功,或 全部 都必須中止並回復作業。 雖然每個微服務內都有內建的交易支援,但分散式交易不支援跨越這五個服務,以保持數據一致。
相反地,您必須 以程序設計方式建構此分散式交易。
新增分散式交易式支援的熱門模式是 Saga模式。 其實作方式是透過程序設計方式將本機交易分組在一起,並循序叫用每個交易。 如果任何本機交易失敗,Saga 會中止作業,並叫用一組 補償交易。 補償交易會復原上述本機交易所做的變更,並恢復資料的一致性。 圖 5-6 顯示具有 Saga 模式的失敗交易。
圖 5-6。 復原交易
在上圖中,庫存更新 作業已在庫存微服務中失敗。 Saga 會叫用一組補償交易(紅色)來調整清查計數、取消付款和訂單,並將每個微服務的數據傳回一致狀態。
Saga 模式通常會編排成一系列相關事件,或編組為一組相關的命令。 在第 4 章中,我們討論了服務匯聚模式,這將是協調的 SAGA 標準程式架構的基礎。 我們也討論了事件以及 Azure 服務總線 和 Azure 事件網格 主題,這些主題是編舞型 Saga 實作的基礎。
大量數據
大型雲端原生應用程式通常支援大量數據需求。 在這些案例中,傳統數據儲存技術可能會導致瓶頸。 對於大規模部署的複雜系統,命令和查詢責任隔離(CQRS)和事件來源都可能會改善應用程式效能。
CQRS
CQRS 是一種架構模式,可協助將效能、延展性和安全性最大化。 此模式會將讀取數據的作業與寫入數據的作業分開。
通常情況下,相同的實體模型和數據存儲庫對象會用於讀取和寫入操作。
然而,在高數據量的情況下,分開的模型和數據表對於讀取和寫入可以帶來好處。 為了改善效能,讀取作業可以查詢高度去正規化的數據表示,以避免因重複的表聯結和表鎖定而產生的高成本。 寫入作業稱為命令,會針對保證一致性之數據的完整正規化表示法進行更新。 接著,您必須實作機制,讓這兩個表示法保持同步。一般而言,每當修改寫入數據表時,就會發佈將修改復寫至讀取數據表 的事件 。
圖 5-7 顯示 CQRS 模式的實作。
圖 5-7。 CQRS 實作
在上圖中,會實作個別的命令和查詢模型。 每個數據寫入作業都會儲存至寫入存放區,然後傳播至讀取存放區。 請密切關注數據傳播程式如何以 最終一致性的原則運作。 讀取模型最終會與寫入模型同步,但程式中可能會有一些延遲。 我們將在下一節討論最終一致性。
此分隔可讓讀取和寫入獨立調整。 讀取作業會使用針對查詢優化的架構,而寫入則使用針對更新優化的架構。 讀取查詢會針對反正規化數據執行,而複雜的商業規則可以套用至寫入模型。 同樣地,您可能會對寫入作業施加比暴露的讀取作業更嚴密的安全措施。
實作 CQRS 可以改善雲端原生服務的應用程式效能。 不過,它確實會產生更複雜的設計。 請謹慎且策略地將此原則套用至雲端原生應用程式的這些區段,以從中獲益。 如需 CQRS 的詳細資訊,請參閱Microsoft書籍 .NET 微服務:容器化 .NET 應用程式的架構。
事件來源
優化大量數據案例的另一種方法包括 事件來源。
系統通常會儲存數據實體的目前狀態。 例如,如果使用者變更其電話號碼,則客戶記錄會以新的號碼更新。 我們一律知道數據實體的目前狀態,但每個更新都會覆寫先前的狀態。
在大部分情況下,此模型運作正常。 不過,在大量系統中,交易式鎖定和頻繁更新作業的額外負荷可能會影響資料庫效能、回應性和限制延展性。
事件來源會採用不同的方法來擷取數據。 影響數據的每個作業都會保存至事件存放區。 我們不會更新數據記錄的狀態,而是將每個變更附加至過去事件的循序列表,類似於會計的總帳。 事件存放區會成為數據的記錄系統。 它用來在微服務的限定內容中傳播各種具體化檢視。 圖 5.8 顯示模式。
圖 5-8。 事件溯源
在上圖中,請注意使用者購物車的每個項目(藍色)如何附加至事件庫。 在相鄰具現化檢視中,系統會重播與每個購物車相關聯的所有事件,以顯示目前的狀態。 然後,此檢視或讀取模型會呈現給使用者介面。 事件也可以與外部系統和應用程式整合,或查詢以判斷實體的目前狀態。 使用這種方法,您會維護歷程記錄。 您不僅知道實體的目前狀態,也知道您達到此狀態的方式。
以機械方式說,事件來源可簡化寫入模型。 沒有更新或刪除。 將每個數據項附加為不可變事件,可將與關係資料庫相關聯的爭用、鎖定和並行衝突降到最低。 使用具體化檢視模式建置讀取模型,可讓您將檢視與寫入模型分離,並選擇最佳的數據存放區,以優化應用程式 UI 的需求。
針對此模式,請考慮直接支援事件來源的數據存放區。 Azure Cosmos DB、MongoDB、Cassandra、CouchDB 和 RavenDB 是很好的候選專案。
如同所有的模式和技術,在策略性的考量下和有需要時實施。 雖然 event sourcing 可以提供更高的效能和擴展性,但代價是增加的複雜性和學習的難度。