雲端原生資料模式

提示

此內容摘錄自《建構適用於 Azure 的雲端原生 .NET 應用程式》電子書,您可以在 .NET Docs 找到此電子書,或免費下載可離線閱讀的 PDF。

Cloud Native .NET apps for Azure eBook cover thumbnail.

如我們在本書中所見,雲端原生方法會變更您設計、部署和管理應用程式的方式。 它也會變更您管理和儲存資料的方式。

圖 5-1 會對比差異。

Data storage in cloud-native applications

圖 5-1. 雲端原生應用程式中的資料管理

有經驗的開發人員可以輕鬆地辨識圖 5-1 左側的架構。 在此「整合型應用程式」中,商務服務元件會共置在共用服務層中,共用來自單一關聯式資料庫的資料。

在許多情況下,單一資料庫會讓資料管理保持簡要。 跨多個資料表查詢資料相當直接明瞭。 資料變更會一起更新,或全部復原。 ACID 交易可保證強式和立即一致性。

針對雲端原生設計,我們會採用不同的方法。 在圖 5-1 的右側,請注意商務功能如何隔離成小型獨立微服務。 每個微服務都會封裝特定商務功能及其本身的資料。 整合型資料庫會分解成具有許多較小資料庫的分散式資料模型,每個資料庫都與微服務一致。 當結果出現後,就會出現一個公開「具各微服務特性的資料庫」之設計。

為何是具各微服務特性的資料庫?

每個微服務的這個資料庫提供許多優點,特別是對於必須快速演進並支援大規模的系統而言。 透過此模型...

  • 網域資料會封裝在服務內
  • 資料結構描述可以在不影響其他服務的情況下演進
  • 每個資料存放區都可以獨立縮放
  • 一個服務中的資料存放區失敗,不會直接影響其他服務

隔離資料也可讓每個微服務針對其工作負載、儲存體需求和讀/寫模式來實作最適合的資料存放區類型。 可用選擇包括關聯式、文件、機碼值,甚至是圖形式資料存放區。

圖 5-2 顯示雲端原生系統中的多語言持續性準則。

Polyglot data persistence

圖 5-2。 多語言資料持續性

請注意,上圖說明每個微服務如何支援不同類型的資料存放區。

  • 產品目錄微服務會取用關聯式資料庫,以容納其基礎資料的豐富關聯式結構。
  • 購物車微服務會取用分散式快取,以支援其簡單的機碼值資料存放區。
  • 訂購微服務會同時取用 NoSQL 文件資料庫來進行寫入作業,以及高度反正規化的機碼值存放區,以容納大量讀取作業。

雖然關聯式資料庫對具有複雜資料的微服務依舊重要,但 NoSQL 資料庫也相當受到歡迎。 它們具有大規模和高可用性。 其沒有架構描述的本質,可讓開發人員移出具類型資料類別和 ORM 的架構,其變更成本昂貴且耗時。 我們將在本章稍後討論 NoSQL 資料庫。

雖然將資料封裝為個別的微服務可以提升靈活度、效能和可擴縮性,但也會呈現許多挑戰。 在下一節中,我們會討論這些挑戰及模式和做法,以協助克服這些挑戰。

跨服務查詢

雖然微服務是獨立的,且著重於特定功能性能力,例如庫存、運送或訂購,但其通常需要與其他微服務整合。 整合通常牽涉到一項微服務「查詢」另一項微服務的資料。 圖 5-3 顯示此案例。

Querying across microservices

圖 5-3。 跨微服務查詢

在上圖中,我們會看到購物籃微服務,其可將項目新增至使用者的購物籃。 雖然此微服務的資料存放區包含購物籃和明細項目資料,但不會維護產品或定價資料。 相反地,這些資料項目是由目錄和定價微服務所擁有。 這方面會呈現一項問題。 購物籃微服務如何在其資料庫中沒有產品或定價資料時,將產品新增至使用者的購物籃?

第 4 章所討論的其中一個選項,是使用從購物籃到目錄和定價微服務的直接 HTTP 呼叫。 不過,在第 4 章中,我們曾說明同步 HTTP 呼叫會將微服務「結合」在一起,減少其自主性並降低其架構優勢。

我們也可以使用每個服務的個別輸入和輸出佇列來實作要求-回覆模式。 不過,此模式十分複雜,且需要管道才能使要求和回應訊息相互關聯。 雖然它會將後端微服務呼叫分離,但呼叫服務仍必須同步等候呼叫完成。 網路壅塞、暫時性錯誤或多載微服務可能會導致長時間執行,甚至是失敗的作業。

相反地,移除跨服務相依性的廣泛接受模式為具體化檢視模式,如圖 5-4 所示。

Materialized view pattern

圖 5-4。 具體化檢視模式

使用此模式時,您會將本機資料表 (也稱為「讀取模型」) 放在購物籃服務內。 下表包含產品與定價微服務所需的資料反正規化複本。 將資料直接複製到購物籃微服務,就不需要昂貴的跨服務呼叫。 透過服務的本機資料,您可以改善服務的回應時間和可靠性。 此外,擁有自己的資料複本,可讓購物籃服務更具復原性。 如果目錄服務因故無法使用,它也不會直接影響購物籃服務。 購物籃可以繼續使用其自有商店的資料。

使用此方法的代價是,現在您系統中有重複的資料。 不過,「策略性地」在雲端原生系統中複製資料是一種既定的做法,而不會被視為反面模式或不良做法。 請記住,「僅有一項服務」可以擁有資料集,並擁有該資料集的授權。 更新記錄系統時,您必須同步處理讀取模型。 同步處理通常是透過具有發佈/訂閱模式的非同步傳訊來實作,如圖 5.4 所示。

分散式交易

雖然跨微服務查詢資料很困難,但跨數個微服務實作交易更為複雜。 在不同微服務中維護獨立資料來源的資料一致性,其固有的挑戰性不言而喻。 若雲端原生應用程式缺乏分散式交易,即代表您必須以程式設計方式來管理分散式交易。 您將從「立即一致性」的世界移至「最終一致性」的世界。

圖 5-5 顯示問題。

Transaction in saga pattern

圖 5-5。 跨微服務實作交易

在上圖中,五個獨立微服務會參與建立訂單的分散式交易。 每個微服務都會維護自有的資料存放區,並為其存放區實作本機交易。 若要建立訂單,則「每個」個別微服務的本機交易都必須成功,或「全部」都必須中止並復原作業。 雖然每個微服務內都有內建的交易支援,但不支援跨越所有五項服務的分散式交易,以保持資料一致。

相反地,您必須以「程式設計方式」建構此分散式交易。

Saga 模式是新增分散式交易式支援的一項熱門模式。 其實作方式是透過程式設計方式將本機交易分組在一起,並循序叫用每個交易。 如果有任何本機交易失敗,則 Saga 會中止作業,並叫用一組補償交易。 補償交易會復原上述本機交易所做的變更,並還原資料一致性。 圖 5-6 顯示 Saga 模式的失敗交易。

Roll back in saga pattern

圖 5-6. 復原交易

在上圖中,庫存微服務中的「更新庫存」作業失敗。 Saga 會叫用一組補償交易 (紅色) 來調整庫存計數、取消付款和訂單,並將每個微服務的資料恢復到一致狀態。

Saga 模式通常會編列為一系列相關事件,或協調為一組相關的命令。 在第 4 章中,我們討論過服務彙總模式,這是受協調 saga 實作的基礎。 我們也討論了事件及 Azure 服務匯流排Azure 事件方格主題,這些主題是編列 saga 實作的基礎。

大量資料

大型雲端原生應用程式通常支援大量資料需求。 在這些情況下,傳統資料儲存技術可能會導致瓶頸。 對於大規模部署的複雜系統,命令與查詢責任隔離 (CQRS) 及事件溯源都可能會改善應用程式效能。

CQRS

CQRS 是一種架構模式,可協助最大化效能、可擴縮性和安全性。 該模式會將讀取資料的作業與寫入資料的作業分離。

針對一般案例,讀取和寫入作業「都會」使用相同的實體模型和資料存放庫物件

不過,大量資料案例可以受益於不同的模型和資料表,以進行讀取和寫入。 若要改善效能,讀取作業可以查詢高度反正規化的資料表示法,以避免昂貴的重複性資料表聯結和資料表鎖定。 「寫入」作業也稱為「命令」,會針對保證一致性之資料的完整正規化表示法進行更新。 接著,您必須實作機制來讓這兩個表示法保持同步。一般而言,每當修改寫入資料表時,就會發佈將修改複寫至讀取資料表的事件

圖 5-7 顯示 CQRS 模式的實作。

Command and Query Responsibility Segregation

圖 5-7。 CQRS 實作

在上圖中,會實作個別的命令和查詢模型。 每個資料寫入作業都會儲存至寫入存放區,然後傳播至讀取存放區。 請特別注意資料傳播流程在最終一致性準則上的運作方式。 讀取模型最終會與寫入模型同步,但流程中可能會有一些延遲。 我們會在下一節討論最終一致性。

此分隔可讓讀取和寫入獨立縮放。 讀取作業會使用針對查詢最佳化的結構描述,而寫入則使用針對更新最佳化的結構描述。 讀取查詢會針對反正規化資料執行,而複雜的商務邏輯可以套用至寫入模型。 此外,您可能會對寫入作業施加比公開讀取更嚴格的安全性。

實作 CQRS 可以改善雲端原生服務的應用程式效能。 不過,這卻會導致更複雜的設計。 請謹慎且策略地將此準則套用至雲端原生應用程式的這些區段,以受益於此準則。 如需 CQRS 的詳細資訊,請參閱 Microsoft 書籍《.NET 微服務:容器化 .NET 應用程式的架構》。

事件來源

最佳化大量資料案例的另一種方法涉及事件溯源

系統通常會儲存資料實體的目前狀態。 例如,如果使用者變更其電話號碼,則會以新號碼更新客戶記錄。 我們一律會知道資料實體的目前狀態,但每個更新都會覆寫先前的狀態。

在大部分情況下,此模型運作正常。 不過,在大量系統中,交易鎖定和頻繁更新作業的額外負荷可能會影響資料庫效能、回應性,並限制可擴縮性。

事件溯源會採用不同的方法來擷取資料。 影響資料的每項作業都會保存到事件存放區。 我們不會更新資料記錄的狀態,而是將每個變更附加至過去事件的循序清單,類似於會計人員的總帳。 事件存放區會成為資料的記錄系統。 它用來在微服務的繫結內容中傳播各種具體化檢視。 圖 5.8 顯示模式。

Event Sourcing

圖 5-8。 事件溯源

在上圖中,請注意使用者購物車的每個項目 (藍色) 如何附加至基礎事件存放區。 在相鄰具體化檢視中,系統會重新執行與每個購物車建立關聯的所有事件,以投影目前的狀態。 然後,此檢視 (或讀取模型) 會公開回 UI。 事件也可以與外部系統和應用程式整合,或經查詢以判斷實體的目前狀態。 使用此方法時,您會維護歷程記錄。 您不僅會知道實體的目前狀態,也知道您達到此狀態的方式。

以機械方式來說,事件溯源可簡化寫入模型。 而且無須進行更新或刪除。 將每個資料項目附加為不可變事件,可將與關聯式資料庫建立關聯的爭用、鎖定和並行衝突降到最低。 使用具體化檢視模式建置讀取模型,可讓您將檢視與寫入模型分離,並選擇最佳的資料存放區,以最佳化應用程式 UI 的需求。

針對此模式,請考慮直接支援事件溯源的資料存放區。 Azure Cosmos DB、MongoDB、Cassandra、CouchDB 和 RavenDB 都是很好的候選項目。

如同所有模式和技術,請視需要策略性地實作。 雖然事件溯源可以提供更高的效能和可擴縮性,但代價會是複雜度和學習曲線。