微服務架構十大架構模式你知道幾個?

軟件設計模式是解決軟件設計中常見問題的通用、可複用的解決方案。設計模式讓咱們能夠分享通用詞彙並使用經實戰檢驗的方案,以避免重複造輪子。如今,我將介紹一系列設計模式來實現這些最佳實踐。html

微服務架構的設計模式

獨享數據庫(Database per Microservice)

當一家公司將大型單體系統替換成一組微服務,首先要面臨的最重要決策是關於數據庫。單體架構會使用大型中央數據庫。即便轉移到微服務架構許多架構師仍傾向於保持數據庫不變。雖然有一些短時間收益,但它倒是反模式的,特別是在大規模系統中,微服務將在數據庫層嚴重耦合,整個遷移到微服務的目標都將面臨失敗(例如,團隊受權、獨立開發等問題)。前端

更好的方法是爲每一個微服務提供本身的數據存儲,這樣服務之間在數據庫層就不存在強耦合。這裏我使用數據庫這一術語來表示邏輯上的數據隔離,也就是說微服務能夠共享物理數據庫,但應該使用分開的數據結構、集合或者表,這還將有助於確保微服務是按照領域驅動設計的方法正確拆分的。java

img圖片程序員

優勢數據庫

  • 數據由服務徹底全部。
  • 服務的開發團隊之間耦合度下降。

缺點後端

  • 服務間的數據共享變得更有挑戰性。
  • 在應用範圍的保證 ACID 事務變得困難許多。
  • 細心設計如何拆分單體數據庫是一項極具挑戰的任務。

什麼時候使用獨享數據庫設計模式

  • 在大型企業應用程序中。
  • 當團隊須要徹底把控微服務以實現開發規模擴展和速度提高。

什麼時候不宜使用獨享數據庫api

  • 在小規模應用中。
  • 若是是單個團隊開發全部微服務。

可用技術示例安全

全部 SQL、 NoSQL 數據庫都提供數據的邏輯分離(例如,單獨的表、集合、結構、數據庫)。markdown

延伸閱讀

微服務模式:獨享數據庫 microservices.io/patterns/da…

分佈式數據存儲 docs.microsoft.com/en-us/dotne…

事件源(Event Sourcing)

在微服務架構中,特別使用獨享數據庫時,微服務之間須要進行數據交換。對於彈性高可伸縮的和可容錯的系統,它們應該經過交換事件進行異步通訊。在這種狀況,您可能但願進行相似更新數據庫併發送消息這樣的原子操做,若是在大數據量的分佈式場景使用關係數據庫,您將沒法使用兩階段鎖協議(2PL),由於它沒法伸縮。而 NoSQL 數據庫由於大多不支持兩階段鎖協議甚至沒法實現分佈式事務。

這裏爲你們準備了一份小小的禮物,關注公衆號【無聊學Java】,輸入以下代碼,便可得到!
0001:《程序員必讀書籍》
0002:《從無到有搭建中小型互聯網公司後臺服務架構與運維架構》
0003:《互聯網企業高併發解決方案》
0004:《Spring Cloud Alibaba實戰視頻》
0006:《SpringBoot實現點餐系統》
0007:《RabbitMQ最新實戰視頻》
0008:《Hadoop實戰教學視頻》
複製代碼

在這些場景,能夠基於事件的架構使用事件源模式。在傳統數據庫中,直接存儲的是業務實體的當前「狀態」,而在事件源中任何「狀態」更新事件或其餘重要事件都會被存儲起來,而不是直接存儲實體自己。這意味着業務實體的全部更改將被保存爲一系列不可變的事件。由於數據是做爲一系列事件存儲的,而非直接更新存儲,因此各項服務能夠經過重放事件存儲中的事件來計算出所需的數據狀態。

img圖片

優勢

  • 爲高可伸縮系統提供原子性操做。
  • 自動記錄實體變動歷史,包括時序回溯功能。
  • 鬆耦合和事件驅動的微服務。

缺點

  • 從事件存儲中讀取實體成爲新的挑戰,一般須要額外的數據存儲(CQRS 模式)。
  • 系統總體複雜性增長了,一般須要領域驅動設計。
  • 系統須要處理事件重複(冪等)或丟失。
  • 變動事件結構成爲新的挑戰。

什麼時候使用事件源

  • 使用關係數據庫的、高可伸縮的事務型系統。
  • 使用 NoSQL 數據庫的事務型系統。
  • 彈性高可伸縮微服務架構。
  • 典型的消息驅動或事件驅動系統(電子商務、預訂和預定系統)。

什麼時候不宜使用事件源

  • 使用 SQL 數據庫的低可伸縮性事務型系統
  • 在服務能夠同步交換數據(例如,經過 API)的簡單微服務架構中。

可用技術示例

事件存儲:EventStoreDB, Apache Kafka, Confluent Cloud, AWS Kinesis, Azure Event Hub, GCP Pub/Sub, Azure Cosmos DB, MongoDB, Cassandra. Amazon DynamoDB

框架: Lagom, Akka, Spring, akkatecture, Axon,Eventuate

延伸閱讀

事件驅動 martinfowler.com/eaaDev/Even…

事件驅動模式-雲設計模式 docs.microsoft.com/en-us/azure…

微服務模式:事件驅動 microservices.io/patterns/da…

命令和查詢職責分離(CQRS)

若是咱們使用事件源,那麼從事件存儲中讀取數據就變得困難了。要從數據存儲中獲取實體,咱們須要處理全部的實體事件。有時咱們對讀寫操做還會有不一樣的一致性和吞吐量要求。

這種狀況,咱們可使用 CQRS 模式。在該模式中,系統的數據修改部分(命令)與數據讀取部分(查詢)是分離的。而 CQRS 模式有兩種容易使人混淆的模式,分別是簡單的和高級的。

在其簡單形式中,不一樣實體或 ORM 模型被用於讀寫操做,以下所示:

img圖片

它有助於強化單一職責原則和分離關注點,從而實現更簡潔的設計。

在其高級形式中,會有不一樣的數據存儲用於讀寫操做。高級的 CQRS 一般結合事件源模式。根據不一樣狀況,會使用不一樣類型的寫數據存儲和讀數據存儲。寫數據存儲是「記錄的系統」,也就是整個系統的核心源頭。

img圖片

對於讀頻繁的應用程序或微服務架構,OLTP 數據庫(任何提供 ACID 事務保證的關係或非關係數據庫)或分佈式消息系統均可以被用做寫存儲。對於寫頻繁的應用程序(寫操做高可伸縮性和大吞吐量),須要使用寫可水平伸縮的數據庫(如全球託管的公共雲數據庫)。標準化的數據則保存在寫數據存儲中。

對搜索(例如 Apache Solr、Elasticsearch)或讀操做(KV 數據庫、文檔數據庫)進行優化的非關係數據庫常被用做讀存儲。許多狀況會在須要 SQL 查詢的地方使用讀可伸縮的關係數據庫。非標準化和特殊優化過的數據則保存在讀存儲中。

數據是從寫存儲異步複製到讀存儲中的,因此讀存儲和寫存儲之間會有延遲,但最終是一致的。

優勢

  • 在事件驅動的微服務中數據讀取速度更快。
  • 數據的高可用性。
  • 讀寫系統可獨立擴展。

缺點

  • 讀數據存儲是弱一致性的(最終一致性)。
  • 整個系統的複雜性增長了,混亂的 CQRS 會顯着危害整個項目。

什麼時候使用 CQRS

  • 在高可擴展的微服務架構中使用事件源。
  • 在複雜領域模型中,讀操做須要同時查詢多個數據存儲。
  • 在讀寫操做負載差別明顯的系統中。

什麼時候不宜使用 CQRS

  • 在沒有必要存儲大量事件的微服務架構中,用事件存儲快照來計算實體狀態是一個更好的選擇。
  • 在讀寫操做負載相近的系統中。

可用技術示例

寫存儲:EventStoreDB, Apache Kafka, Confluent Cloud, AWS Kinesis, Azure Event Hub, GCP Pub/Sub, Azure Cosmos DB, MongoDB, Cassandra. Amazon DynamoDB

讀存儲: Elastic Search, Solr, Cloud Spanner, Amazon Aurora, Azure Cosmos DB, Neo4j

框架: Lagom, Akka, Spring, akkatecture, Axon, Eventuate

延伸閱讀

bliki:CQRS martinfowler.com/bliki/CQRS.…

CQRS模式 - Azure 架構中心 docs.microsoft.com/en-us/azure…

微服務模式:命令和查詢職責分離(CQRS) microservices.io/patterns/da…

Saga

若是微服務使用獨享數據庫,那麼經過分佈式事務管理一致性是一個巨大的挑戰。你沒法使用傳統的兩階段提交協議,由於它要麼不可伸縮(關係數據庫),要麼不被支持(多數非關係數據庫)。

但您仍是能夠在微服務架構中使用 Saga 模式實現分佈式事務。Saga 是 1987 年開發的一種古老模式,是關係數據庫中關於大事務的一個替代概念。但這種模式的一種現代變種對分佈式事務也很是有效。Saga 模式是一個本地事務序列,其每一個事務在一個單獨的微服務內更新數據存儲併發佈一個事件或消息。Saga 中的首個事務是由外部請求(事件或動做)初始化的,一旦本地事務完成(數據已保存在數據存儲且消息或事件已發佈),那麼發佈的消息或事件則會觸發 Saga 中的下一個本地事務。

img圖片

若是本地事務失敗,Saga 將執行一系列補償事務來回滾前面本地事務的更改。

Saga 事務協調管理主要有兩種形式:

  • 事件編排 Choreography:分散協調,每一個微服務生產並監聽其餘微服務的事件或消息而後決定是否執行某個動做。
  • 命令編排 Orchestration:集中協調,由一個協調器告訴參與的微服務哪一個本地事務須要執行。

優勢

  • 爲高可伸縮或鬆耦合的、事件驅動的微服務架構提供一致性事務。
  • 爲使用了不支持 2PC 的非關係數據庫的微服務架構提供一致性事務。

缺點

  • 須要處理瞬時故障,而且提供等冪性。
  • 難以調試,並且複雜性隨着微服務數量增長而增長。

什麼時候使用 Saga

  • 在使用了事件源的高可伸縮、鬆耦合的微服務中。
  • 在使用了分佈式非關係數據庫的系統中。

什麼時候不宜使用 Saga

  • 使用關係數據庫的低可伸縮性事務型系統。
  • 在服務間存在循環依賴的系統中。

可用技術示例

Axon, Eventuate, Narayana

延伸閱讀

Saga分佈式事務-Azure設計模式 docs.microsoft.com/en-us/azure…

微服務模式:Sagas microservices.io/patterns/da…

Saga 模式:微服務中的應用程序事務 blog.couchbase.com/saga-patter…

面向前端的後端 (BFF)

在現代商業應用開發,特別是微服務架構中,先後端應用是分離和獨立的服務,它們經過 API 或 GraphQL 鏈接。若是應用程序還有移動 App 客戶端,那麼 Web 端和移動客戶端使用相同的後端微服務就會出現問題。由於移動客戶端和 Web 客戶端有不一樣的屏幕尺寸、顯示屏、性能、能耗和網絡帶寬,它們的 API 需求不一樣。

面向前端的後端模式適用於須要爲特殊 UI 定製單獨後端的場景。它還提供了其餘優點,好比做爲下游微服務的封裝,從而減小 UI 和下游微服務之間的頻繁通訊。此外,在高安全要求的場景中,BFF 爲部署在 DMZ 網絡中的下游微服務提供了更高的安全性。

img圖片

優勢

  • 分離 BFF 之間的關注點,使得咱們能夠爲具體的 UI 優化他們。
  • 提供更高的安全性。
  • 減小 UI 和下游微服務之間頻繁的通訊。

缺點

  • BFF 之間代碼重複。
  • 大量的 BFF 用於其餘用戶界面(例如,智能電視,Web,移動端,PC 桌面版)。
  • 須要仔細的設計和實現,BFF 不該該包含任何業務邏輯,而應只包含特定客戶端邏輯和行爲。

什麼時候使用 BFF

  • 若是應用程序有多個含不一樣 API 需求的 UI。
  • 出於安全須要,UI 和下游微服務之間須要額外的層。
  • 若是在 UI 開發中使用微前端。

什麼時候不宜使用 BFF

  • 若是應用程序雖有多個 UI,但使用的 API 相同。
  • 若是核心微服務不是部署在 DMZ 網絡中。

可用技術示例

任何後端框架(Node.js,Spring,Django,Laravel,Flask,Play,…)都能支持。

延伸閱讀

Sam Newman - 面向前端的後端 samnewman.io/patterns/ar…

面向前端的後端模式 - 雲設計模式 docs.microsoft.com/en-us/azure…

微服務模式:API 網關模式 microservices.io/patterns/ap…

API 網關

在微服務架構中,UI 一般鏈接多個微服務。若是微服務是細粒度的(FaaS) ,那麼客戶端可能須要鏈接很是多的微服務,這將變得繁雜和具備挑戰性。此外,這些服務包括它們的 API 還將不斷進化。大型企業還但願能有其餘橫切關注點(SSL 終止、身份驗證、受權、節流、日誌記錄等)。

一個解決這些問題的可行方法是使用 API 網關。API 網關位於客戶端 APP 和後端微服務之間充當 facade,它能夠是反向代理,將客戶端請求路由到適當的後端微服務。它還支持將客戶端請求扇出到多個微服務,而後將響應聚合後返回給客戶端。它還支持必要的橫切關注點。

img圖片

優勢

  • 在前端和後端服務之間提供鬆耦合。
  • 減小客戶端和微服務之間的調用次數。
  • 經過 SSL 終端、身份驗證和受權實現高安全性。
  • 集中管理的橫切關注點,例如,日誌記錄和監視、節流、負載平衡。

缺點

  • 可能致使微服務架構中的單點故障。
  • 額外的網絡調用帶來的延遲增長。
  • 若是不進行擴展,它們很容易成爲整個企業應用的瓶頸。
  • 額外的維護和開發費用。

什麼時候使用 API 網關

  • 在複雜的微服務架構中,它幾乎是必須的。
  • 在大型企業中,API 網關是中心化安全性和橫切關注點的必要工具。

什麼時候不宜使用 API 網關

  • 在安全和集中管理不是最優先要素的私人項目或小公司中。
  • 若是微服務的數量至關少。

可用技術示例

Amazon API 網關, Azure API 管理, Apigee, Kong, WSO2 API 管理器

延伸閱讀

微服務模式:API 網關模式 microservices.io/patterns/ap…

API 網關-Azure 架構中心 docs.microsoft.com/en-us/azure…

Strangler

若是想在運行中的項目中使用微服務架構,咱們須要將遺留的或現有的單體應用遷移到微服務。將現有的大型在線單體應用程序遷移到微服務是至關有挑戰性的,由於這可能破壞應用程序的可用性。

一個解決方案是使用 Strangler 模式。Strangler 模式意味着經過使用新的微服務逐步替換特定功能,將單體應用程序增量地遷移到微服務架構。此外,新功能只在微服務中添加,而再也不添加到遺留的單體應用中。而後配置一個 Facade (API 網關)來路由遺留單體應用和微服務間的請求。當某個功能從單體應用遷移到微服務,Facade 就會攔截客戶端請求並路由到新的微服務。一旦遷移了全部的功能,遺留單體應用程序就會被「扼殺(Strangler)」,即退役。

img

優勢

  • 安全的遷移單體應用程序到微服務。
  • 能夠並行地遷移已有功能和開發新功能。
  • 遷移過程能夠更好把控節奏。

缺點

  • 在現有的單體應用服務和新的微服務之間共享數據存儲變得具備挑戰性。
  • 添加 Facade (API 網關)將增長系統延遲。
  • 端到端測試變得困難。

什麼時候使用 Strangler

  • 將大型後端單體應用程序的增量遷移到微服務。

什麼時候不宜使用 Strangler

  • 若是後端單體應用很小,那麼全量替換會更好。
  • 若是沒法攔截客戶端對遺留的單體應用程序的請求。

可用技術示例

API 網關後端應用框架。

延伸閱讀

bliki:StranglerFig 應用程序 martinfowler.com/bliki/Stran…

Strangler 模式 - 雲設計模式 docs.microsoft.com/en-us/azure…

微服務模式:Strangler 應用程序 microservices.io/patterns/re…

斷路器

在微服務架構中,微服務經過同步調用其餘服務來知足業務需求。服務調用會因爲瞬時故障(網絡鏈接緩慢、超時或暫時不可用) 致使失敗,這種狀況重試能夠解決問題。然而,若是出現了嚴重問題(微服務徹底失敗),那麼微服務將長時間不可用,這時重試沒有意義且浪費寶貴的資源(線程被阻塞,CPU 週期被浪費)。此外,一個服務的故障還會引起整個應用系統的級聯故障。這時快速失敗是一種更好的方法。

在這種狀況,可使用斷路器模式挽救。一個微服務經過代理請求另外一個微服務,其工做原理相似於電氣斷路器,代理經過統計最近發生的故障數量,並使用它來決定是繼續請求仍是簡單的直接返回異常。

img

斷路器能夠有如下三種狀態:

  • 關閉:斷路器將請求路由到微服務,並統計給定時段內的故障數量,若是超過閾值,它就會觸發並進入打開狀態。
  • 打開:來自微服務的請求會快速失敗並返回異常。在超時後,斷路器進入半開啓狀態。
  • 半開:只有有限數量的微服務請求被容許經過並進行調用。若是這些請求成功,斷路器將進入閉合狀態。若是任何請求失敗,斷路器則會進入開啓狀態。

優勢

  • 提升微服務架構的容錯性和彈性。
  • 阻止引起其餘微服務的級聯故障。

缺點

  • 須要複雜的異常處理。
  • 日誌和監控。
  • 應該支持人工復位。

什麼時候使用斷路器

  • 在微服務間使用同步通訊的緊耦合的微服務架構中。
  • 若是微服務依賴多個其餘微服務。

什麼時候不宜使用斷路器

  • 鬆耦合、事件驅動的微服務架構。
  • 若是微服務不依賴於其餘微服務。

可用技術示例

API 網關,服務網格,各類斷路器庫(Hystrix, Reselience4J, Polly)。

延伸閱讀

bliki:斷路器 martinfowler.com/bliki/Circu…

斷路器模式 - 雲設計模式 docs.microsoft.com/en-us/azure…

微型服務模式:斷路器 microservices.io/patterns/re…

外部化配置

每一個業務應用都有許多用於各類基礎設施的配置參數(例如,數據庫、網絡、鏈接的服務地址、憑據、證書路徑)。此外在企業應用程序一般部署在各類運行環境(Local、 Dev、 Prod)中,實現這些的一個方法是經過內部配置。這是一個致命糟糕實踐,它會致使嚴重的安全風險,由於生產憑證很容易遭到破壞。此外,配置參數的任何更改都須要從新構建應用程序,這在在微服務架構中會更加嚴峻,由於咱們可能擁有數百個服務。

更好的方法是將全部配置外部化,使得構建過程與運行環境分離,生產的配置文件只在運行時或經過環境變量使用,從而最小化了安全風險。

優勢

  • 生產配置不屬於代碼庫,於是最小化了安全漏洞。
  • 修改配置參數不須要從新構建應用程序。

缺點

  • 咱們須要選擇一個支持外部化配置的框架。

什麼時候使用外部化配置

  • 任何重要的生產應用程序都必須使用外部化配置。

什麼時候不宜使用外部化配置

  • 在驗證概念的開發中。

可用技術示例

幾乎全部企業級的現代框架都支持外部化配置。

延伸閱讀

微服務模式:外部化配置 microservices.io/patterns/ex…

一次構建,處處運行:外部化你的配置 reflectoring.io/externalize…

消費端驅動的契約測試

在微服務架構中,一般有許多有不一樣團隊開發的微服務。這些微型服務協同工做來知足業務需求(例如,客戶請求),並相互進行同步或異步通訊。消費端微服務的集成測試具備挑戰性,一般用 TestDouble 以得到更快、更低成本的測試運行。可是 TestDouble 一般並不能表明真正的微服務提供者,並且若是微服務提供者更改了它的 API 或 消息,那麼 TestDouble 將沒法確認這些。另外一種選擇是進行端到端測試,儘管它在生產以前是強制性的,但倒是脆弱的、緩慢的、昂貴的且不能替代集成測試(Test Pyramid)。

在這方面消費端驅動的契約測試能夠幫助咱們。在這裏,負責消費端微服務的團隊針對特定的服務端微服務,編寫一套包含了其請求和預期響應(同步)或消息(異步)的測試套件,這些測試套件稱爲顯式的約定。對於微服務服務端,將其消費端全部約定的測試套件都添加到其自動化測試中。當特定服務端微服務的自動化測試執行時,它將一塊兒運行本身的測試和約定的測試並進行驗證。經過這種方式,契約測試能夠自動的幫助維護微服務通訊的完整性。

優勢

  • 若是提供程序意外更改 API 或消息,能夠被快速的自動發現。
  • 更少意外、更健壯,特別是包含大量微服務的企業應用程序。
  • 改善團隊自主性。

缺點

  • 須要額外的工做來開發和集成微服務服務端的契約測試,由於他們可能使用徹底不一樣的測試工具。
  • 若是契約測試與真實服務狀況不匹配,將可能致使生產故障。

什麼時候使用需求驅動的契約測試

  • 在大型企業業務應用程序中,一般由不一樣的團隊開發不一樣服務。

什麼時候不宜使用消費端驅動的契約測試

  • 全部微服務由同一團隊負責開發的小型簡單的應用程序。
  • 若是服務端微服務是相對穩定的,而且不處在活躍的開發狀態。

可用技術示例

Pact, Postman, Spring Cloud Contract

延伸閱讀

需求驅動契約:一種服務演進模式 martinfowler.com/articles/co…

微服務模式:服務集成契約測試 microservices.io/patterns/te…

什麼是消費端驅動的契約測試? pactflow.io/what-is-con…

總結

在現代大規模企業軟件開發中,微服務架構可以幫助開發擴展規模並帶來不少長期收益。可是微服務架構並非隨處可用的銀彈,若是應用在錯誤的應用程序類型,微服務架構將弊大於利。但願採用微服務架構的開發團隊應該遵循最佳實踐,並使用一系列可重用的、久經錘鍊的設計模式。

微服務架構中相當重要的設計模式是獨享數據庫。實現這種設計模式具備挑戰性,須要其餘幾種密切相關的設計模式(事件驅動、 CQRS、 Saga)來支持。在具備多個客戶端(Web、 Mobile、 Desktop、 Smart Devices)的典型業務應用程序中,客戶端和微服務之間的通訊量多是很大的,而且須要統一的安全控制,在這種狀況面向前端的後端API 網關的設計很是有用。此外,斷路器模式能夠大大地幫助應對這類應用程序的錯誤處理場景。遷移遺留的單體應用到微服務是極具挑戰性的,而 Strangler 模式能夠幫助作到這點。消費端驅動的契約測試是微服務集成測試的基礎模式。另外外部化配置是任何現代化應用程序開發中的一種必備模式。

這個系列並不全面,在實際狀況中您可能須要其餘的設計模式,但這個系列能爲您提供一個關於微服務架構設計模式的極好介紹

相關文章
相關標籤/搜索