微服務(wù)架構(gòu)及其最重要的10個設(shè)計模式

從軟件開發(fā)早期(1960 年代)開始,應(yīng)對大型軟件系統(tǒng)中的復(fù)雜性一直是一項令人生畏的任務(wù)。多年來為了應(yīng)對軟件系統(tǒng)的復(fù)雜性,軟件工程師和架構(gòu)師們做了許多嘗試:David Parnas 的模塊化和封裝 (1972), Edsger W. Dijkstra (1974)的關(guān)注點分離以及 SOA(1988)。
他們都是使用分而治之這項成熟的傳統(tǒng)技術(shù)來應(yīng)對大型系統(tǒng)的復(fù)雜性。自 2010 年開始,這些技術(shù)被證實無法繼續(xù)應(yīng)對 Web 級應(yīng)用或者現(xiàn)代大型企業(yè)級應(yīng)用的復(fù)雜性。因此架構(gòu)師和工程師們發(fā)展出了一種全新的現(xiàn)代方式來解決這個問題,就是微服務(wù)架構(gòu)。它雖然延續(xù)了分而治之的思想,但卻是以全新的方式來實現(xiàn)的。
軟件設(shè)計模式是解決軟件設(shè)計中常見問題的通用、可復(fù)用的解決方案。設(shè)計模式讓我們可以分享通用詞匯并使用經(jīng)實戰(zhàn)檢驗的方案,以免重復(fù)造輪子。我先簡單介紹下微服務(wù)架構(gòu)。
通過閱讀這篇文章,你會學(xué)到:
微服務(wù)架構(gòu)
微服務(wù)架構(gòu)的優(yōu)勢
微服務(wù)架構(gòu)的劣勢
何時使用微服務(wù)架構(gòu)
最重要的微服務(wù)架構(gòu)設(shè)計模式,包括其優(yōu)缺點、用例、上下文、技術(shù)棧示例及可用資源。
請注意,本清單中的大部分設(shè)計模式常出現(xiàn)在多種語境中,并且可以在非微服務(wù)架構(gòu)中使用。而我將在微服務(wù)這個特定語境中介紹它們。
我在之前的博客《微服務(wù)架構(gòu)概述及為什么要應(yīng)用在下個項目》和《單體軟件架構(gòu)真的終結(jié)了嗎?》中對微服務(wù)架構(gòu)有非常詳盡的介紹。如果你感興趣,可以閱讀這兩篇博客來深入了解。
https://towardsdatascience.com/microservice-architecture-a-brief-overview-and-why-you-should-use-it-in-your-next-project-a17b6e19adfd
https://towardsdatascience.com/looking-beyond-the-hype-is-modular-monolithic-software-architecture-really-dead-e386191610f8
那到底什么是微服務(wù)架構(gòu)?有很多種定義方法。我的定義是這這樣的:
微服務(wù)架構(gòu)指的是將大型復(fù)雜系統(tǒng)按功能或者業(yè)務(wù)需求垂直切分成更小的子系統(tǒng),這些子系統(tǒng)以獨立部署的子進程存在,它們之間通過輕量級的、跨語言的同步(比如 REST,gRPC)或者異步(消息)網(wǎng)絡(luò)調(diào)用進行通信。
下面是基于微服務(wù)架構(gòu)的商業(yè) Web 應(yīng)用的組件視圖:

來自 Md Kamaruzzaman 的微服務(wù)架構(gòu)
整個應(yīng)用程序被拆分成相互獨立但包含多個內(nèi)部模塊的子進程
與模塊化的單體應(yīng)用(Modular Monoliths)或 SOA 相反,微服務(wù)應(yīng)用程序根據(jù)業(yè)務(wù)范圍或領(lǐng)域垂直拆分。
微服務(wù)邊界是外部的,微服務(wù)之間通過網(wǎng)絡(luò)調(diào)用(RPC 或消息)相互通信。
微服務(wù)是獨立的進程,它們可以獨立部署。
它們以輕量級的方式進行通信,不需要任何智能通信通道。
更好的開發(fā)規(guī)模
更快的開發(fā)速度
支持迭代開發(fā)或現(xiàn)代化增量開發(fā)
充分利用現(xiàn)代軟件開發(fā)生態(tài)系統(tǒng)的優(yōu)勢(云、容器、 DevOps、Serverless)
支持水平縮放和細(xì)粒度縮放
小體量,較低了開發(fā)人員的認(rèn)知復(fù)雜性
更高數(shù)量級的活動組件(服務(wù)、數(shù)據(jù)庫、進程、容器、框架)
復(fù)雜性從代碼轉(zhuǎn)移到基礎(chǔ)設(shè)施
RPC 調(diào)用和網(wǎng)絡(luò)通信的大量增加
整個系統(tǒng)的安全性管理更具有挑戰(zhàn)性
整個系統(tǒng)的設(shè)計變得更加困難
引入了分布式系統(tǒng)的復(fù)雜性
大規(guī)模 Web 應(yīng)用開發(fā)
跨團隊企業(yè)級應(yīng)用協(xié)作開發(fā)
長期收益優(yōu)先于短期收益
團隊擁有能夠設(shè)計微服務(wù)架構(gòu)的軟件架構(gòu)師或高級工程師
當(dāng)一家公司將大型單體系統(tǒng)替換成一組微服務(wù),首先要面臨的最重要決策是關(guān)于數(shù)據(jù)庫。單體架構(gòu)會使用大型中央數(shù)據(jù)庫。即使轉(zhuǎn)移到微服務(wù)架構(gòu)許多架構(gòu)師仍傾向于保持?jǐn)?shù)據(jù)庫不變。雖然有一些短期收益,但它卻是反模式的,特別是在大規(guī)模系統(tǒng)中,微服務(wù)將在數(shù)據(jù)庫層嚴(yán)重耦合,整個遷移到微服務(wù)的目標(biāo)都將面臨失?。ɡ?,團隊授權(quán)、獨立開發(fā)等問題)。
更好的方法是為每個微服務(wù)提供自己的數(shù)據(jù)存儲,這樣服務(wù)之間在數(shù)據(jù)庫層就不存在強耦合。這里我使用數(shù)據(jù)庫這一術(shù)語來表示邏輯上的數(shù)據(jù)隔離,也就是說微服務(wù)可以共享物理數(shù)據(jù)庫,但應(yīng)該使用分開的數(shù)據(jù)結(jié)構(gòu)、集合或者表,這還將有助于確保微服務(wù)是按照領(lǐng)域驅(qū)動設(shè)計的方法正確拆分的。

Md Kamaruzzaman 的微服務(wù)獨享數(shù)據(jù)庫
優(yōu)點
數(shù)據(jù)由服務(wù)完全所有
服務(wù)的開發(fā)團隊之間耦合度降低
缺點
服務(wù)間的數(shù)據(jù)共享變得更有挑戰(zhàn)性
在應(yīng)用范圍的保證 ACID 事務(wù)變得困難許多
細(xì)心設(shè)計如何拆分單體數(shù)據(jù)庫是一項極具挑戰(zhàn)的任務(wù)
何時使用獨享數(shù)據(jù)庫
在大型企業(yè)應(yīng)用程序中
當(dāng)團隊需要完全把控微服務(wù)以實現(xiàn)開發(fā)規(guī)模擴展和速度提升
何時不宜使用獨享數(shù)據(jù)庫
在小規(guī)模應(yīng)用中
如果是單個團隊開發(fā)所有微服務(wù)
可用技術(shù)示例
所有 SQL、 NoSQL 數(shù)據(jù)庫都提供數(shù)據(jù)的邏輯分離(例如,單獨的表、集合、結(jié)構(gòu)、數(shù)據(jù)庫)。
在微服務(wù)架構(gòu)中,特別使用獨享數(shù)據(jù)庫時,微服務(wù)之間需要進行數(shù)據(jù)交換。對于彈性高可伸縮的和可容錯的系統(tǒng),它們應(yīng)該通過交換事件進行異步通信。在這種情況,您可能希望進行類似更新數(shù)據(jù)庫并發(fā)送消息這樣的原子操作,如果在大數(shù)據(jù)量的分布式場景使用關(guān)系數(shù)據(jù)庫,您將無法使用兩階段鎖協(xié)議(2PL),因為它無法伸縮。而 NoSQL 數(shù)據(jù)庫因為大多不支持兩階段鎖協(xié)議甚至無法實現(xiàn)分布式事務(wù)。
在這些場景,可以基于事件的架構(gòu)使用事件源模式。在傳統(tǒng)數(shù)據(jù)庫中,直接存儲的是業(yè)務(wù)實體的當(dāng)前“狀態(tài)”,而在事件源中任何“狀態(tài)”更新事件或其他重要事件都會被存儲起來,而不是直接存儲實體本身。這意味著業(yè)務(wù)實體的所有更改將被保存為一系列不可變的事件。因為數(shù)據(jù)是作為一系列事件存儲的,而非直接更新存儲,所以各項服務(wù)可以通過重放事件存儲中的事件來計算出所需的數(shù)據(jù)狀態(tài)。

Md Kamaruzzaman 的事件源
優(yōu)點
為高可伸縮系統(tǒng)提供原子性操作
自動記錄實體變更歷史,包括時序回溯功能
松耦合和事件驅(qū)動的微服務(wù)
缺點
從事件存儲中讀取實體成為新的挑戰(zhàn),通常需要額外的數(shù)據(jù)存儲(CQRS 模式)。
系統(tǒng)整體復(fù)雜性增加了,通常需要領(lǐng)域驅(qū)動設(shè)計。
系統(tǒng)需要處理事件重復(fù)(冪等)或丟失
變更事件結(jié)構(gòu)成為新的挑戰(zhàn)。
何時使用事件源
使用關(guān)系數(shù)據(jù)庫的、高可伸縮的事務(wù)型系統(tǒng)
使用 NoSQL 數(shù)據(jù)庫的事務(wù)型系統(tǒng)
彈性高可伸縮微服務(wù)架構(gòu)
典型的消息驅(qū)動或事件驅(qū)動系統(tǒng)(電子商務(wù)、預(yù)訂和預(yù)約系統(tǒng))
何時不宜使用事件源
使用 SQL 數(shù)據(jù)庫的低可伸縮性事務(wù)型系統(tǒng)
在服務(wù)可以同步交換數(shù)據(jù)(例如,通過 API)的簡單微服務(wù)架構(gòu)中。
可用技術(shù)示例
事件存儲: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
如果我們使用事件源,那么從事件存儲中讀取數(shù)據(jù)就變得困難了。要從數(shù)據(jù)存儲中獲取實體,我們需要處理所有的實體事件。有時我們對讀寫操作還會有不同的一致性和吞吐量要求。
這種情況,我們可以使用 CQRS 模式。在該模式中,系統(tǒng)的數(shù)據(jù)修改部分(命令)與數(shù)據(jù)讀取部分(查詢)是分離的。而 CQRS 模式有兩種容易令人混淆的模式,分別是簡單的和高級的。
在其簡單形式中,不同實體或 ORM 模型被用于讀寫操作,如下所示:

Md Kamaruzzaman 的 CQRS (簡單)
它有助于強化單一職責(zé)原則和分離關(guān)注點,從而實現(xiàn)更簡潔的設(shè)計。
在其高級形式中,會有不同的數(shù)據(jù)存儲用于讀寫操作。高級的 CQRS 通常結(jié)合事件源模式。根據(jù)不同情況,會使用不同類型的寫數(shù)據(jù)存儲和讀數(shù)據(jù)存儲。寫數(shù)據(jù)存儲是“記錄的系統(tǒng)”,也就是整個系統(tǒng)的核心源頭。

Md Kamaruzzaman 的 CQRS(高級)
對于讀頻繁的應(yīng)用程序或微服務(wù)架構(gòu),OLTP 數(shù)據(jù)庫(任何提供 ACID 事務(wù)保證的關(guān)系或非關(guān)系數(shù)據(jù)庫)或分布式消息系統(tǒng)都可以被用作寫存儲。對于寫頻繁的應(yīng)用程序(寫操作高可伸縮性和大吞吐量),需要使用寫可水平伸縮的數(shù)據(jù)庫(如全球托管的公共云數(shù)據(jù)庫)。標(biāo)準(zhǔn)化的數(shù)據(jù)則保存在寫數(shù)據(jù)存儲中。
對搜索(例如 Apache Solr、Elasticsearch)或讀操作(KV 數(shù)據(jù)庫、文檔數(shù)據(jù)庫)進行優(yōu)化的非關(guān)系數(shù)據(jù)庫常被用作讀存儲。許多情況會在需要 SQL 查詢的地方使用讀可伸縮的關(guān)系數(shù)據(jù)庫。非標(biāo)準(zhǔn)化和特殊優(yōu)化過的數(shù)據(jù)則保存在讀存儲中。
數(shù)據(jù)是從寫存儲異步復(fù)制到讀存儲中的,所以讀存儲和寫存儲之間會有延遲,但最終是一致的。
在公眾號互聯(lián)網(wǎng)架構(gòu)師回復(fù)“2T”,獲取驚喜禮包。
優(yōu)點
在事件驅(qū)動的微服務(wù)中數(shù)據(jù)讀取速度更快
數(shù)據(jù)的高可用性
讀寫系統(tǒng)可獨立擴展
缺點
讀數(shù)據(jù)存儲是弱一致性的(最終一致性)
整個系統(tǒng)的復(fù)雜性增加了,混亂的 CQRS 會顯著危害整個項目。
何時使用 CQRS
在高可擴展的微服務(wù)架構(gòu)中使用事件源
在復(fù)雜領(lǐng)域模型中,讀操作需要同時查詢多個數(shù)據(jù)存儲。
在讀寫操作負(fù)載差異明顯的系統(tǒng)中
何時不宜使用 CQRS
在沒有必要存儲大量事件的微服務(wù)架構(gòu)中,用事件存儲快照來計算實體狀態(tài)是一個更好的選擇。
在讀寫操作負(fù)載相近的系統(tǒng)中。
可用技術(shù)示例
寫存儲: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
如果微服務(wù)使用獨享數(shù)據(jù)庫,那么通過分布式事務(wù)管理一致性是一個巨大的挑戰(zhàn)。你無法使用傳統(tǒng)的兩階段提交協(xié)議,因為它要么不可伸縮(關(guān)系數(shù)據(jù)庫),要么不被支持(多數(shù)非關(guān)系數(shù)據(jù)庫)。
但您還是可以在微服務(wù)架構(gòu)中使用 Saga 模式實現(xiàn)分布式事務(wù)。Saga 是 1987 年開發(fā)的一種古老模式,是關(guān)系數(shù)據(jù)庫中關(guān)于大事務(wù)的一個替代概念。但這種模式的一種現(xiàn)代變種對分布式事務(wù)也非常有效。Saga 模式是一個本地事務(wù)序列,其每個事務(wù)在一個單獨的微服務(wù)內(nèi)更新數(shù)據(jù)存儲并發(fā)布一個事件或消息。Saga 中的首個事務(wù)是由外部請求(事件或動作)初始化的,一旦本地事務(wù)完成(數(shù)據(jù)已保存在數(shù)據(jù)存儲且消息或事件已發(fā)布),那么發(fā)布的消息或事件則會觸發(fā) Saga 中的下一個本地事務(wù)。

Md Kamaruzzaman 的 Saga
如果本地事務(wù)失敗,Saga 將執(zhí)行一系列補償事務(wù)來回滾前面本地事務(wù)的更改。
Saga 事務(wù)協(xié)調(diào)管理主要有兩種形式:
事件編排 Choreography:分散協(xié)調(diào),每個微服務(wù)生產(chǎn)并監(jiān)聽其他微服務(wù)的事件或消息然后決定是否執(zhí)行某個動作。
命令編排 Orchestration:集中協(xié)調(diào),由一個協(xié)調(diào)器告訴參與的微服務(wù)哪個本地事務(wù)需要執(zhí)行。
優(yōu)點
為高可伸縮或松耦合的、事件驅(qū)動的微服務(wù)架構(gòu)提供一致性事務(wù)。
為使用了不支持 2PC 的非關(guān)系數(shù)據(jù)庫的微服務(wù)架構(gòu)提供一致性事務(wù)。
缺點
需要處理瞬時故障,并且提供等冪性。
難以調(diào)試,而且復(fù)雜性隨著微服務(wù)數(shù)量增加而增加。
何時使用 Saga
在使用了事件源的高可伸縮、松耦合的微服務(wù)中。
在使用了分布式非關(guān)系數(shù)據(jù)庫的系統(tǒng)中。
何時不宜使用 Saga
使用關(guān)系數(shù)據(jù)庫的低可伸縮性事務(wù)型系統(tǒng)。
在服務(wù)間存在循環(huán)依賴的系統(tǒng)中。
可用技術(shù)示例
Axon, Eventuate, Narayana
在現(xiàn)代商業(yè)應(yīng)用開發(fā),特別是微服務(wù)架構(gòu)中,前后端應(yīng)用是分離和獨立的服務(wù),它們通過 API 或 GraphQL 連接。如果應(yīng)用程序還有移動 App 客戶端,那么 Web 端和移動客戶端使用相同的后端微服務(wù)就會出現(xiàn)問題。因為移動客戶端和 Web 客戶端有不同的屏幕尺寸、顯示屏、性能、能耗和網(wǎng)絡(luò)帶寬,它們的 API 需求不同。
面向前端的后端模式適用于需要為特殊 UI 定制單獨后端的場景。它還提供了其他優(yōu)勢,比如作為下游微服務(wù)的封裝,從而減少 UI 和下游微服務(wù)之間的頻繁通信。此外,在高安全要求的場景中,BFF 為部署在 DMZ 網(wǎng)絡(luò)中的下游微服務(wù)提供了更高的安全性。

Md Kamaruzzaman 的面向前端的后端
優(yōu)點
分離 BFF 之間的關(guān)注點,使得我們可以為具體的 UI 優(yōu)化他們。
提供更高的安全性
減少 UI 和下游微服務(wù)之間頻繁的通信
缺點
BFF 之間代碼重復(fù)
大量的 BFF 用于其他用戶界面(例如,智能電視,Web,移動端,PC 桌面版)
需要仔細(xì)的設(shè)計和實現(xiàn),BFF 不應(yīng)該包含任何業(yè)務(wù)邏輯,而應(yīng)只包含特定客戶端邏輯和行為。
何時使用 BFF
如果應(yīng)用程序有多個含不同 API 需求的 UI
出于安全需要,UI 和下游微服務(wù)之間需要額外的層。
如果在 UI 開發(fā)中使用微前端。
何時不宜使用 BFF
如果應(yīng)用程序雖有多個 UI,但使用的 API 相同。
如果核心微服務(wù)不是部署在 DMZ 網(wǎng)絡(luò)中。
可用技術(shù)示例
任何后端框架(Node.js,Spring,Django,Laravel,F(xiàn)lask,Play,…)都能支持。
在微服務(wù)架構(gòu)中,UI 通常連接多個微服務(wù)。如果微服務(wù)是細(xì)粒度的(FaaS) ,那么客戶端可能需要連接非常多的微服務(wù),這將變得繁雜和具有挑戰(zhàn)性。此外,這些服務(wù)包括它們的 API 還將不斷進化。大型企業(yè)還希望能有其他橫切關(guān)注點(SSL 終止、身份驗證、授權(quán)、節(jié)流、日志記錄等)。
在公眾號互聯(lián)網(wǎng)架構(gòu)師后臺回復(fù)“2T”,獲取Java面試題和答案驚喜禮包。
一個解決這些問題的可行方法是使用 API 網(wǎng)關(guān)。API 網(wǎng)關(guān)位于客戶端 APP 和后端微服務(wù)之間充當(dāng) facade,它可以是反向代理,將客戶端請求路由到適當(dāng)?shù)暮蠖宋⒎?wù)。它還支持將客戶端請求扇出到多個微服務(wù),然后將響應(yīng)聚合后返回給客戶端。它還支持必要的橫切關(guān)注點。

Md Kamaruzzaman 的 API 網(wǎng)關(guān)
優(yōu)點
在前端和后端服務(wù)之間提供松耦合
減少客戶端和微服務(wù)之間的調(diào)用次數(shù)
通過 SSL 終端、身份驗證和授權(quán)實現(xiàn)高安全性
集中管理的橫切關(guān)注點,例如,日志記錄和監(jiān)視、節(jié)流、負(fù)載平衡。
缺點
可能導(dǎo)致微服務(wù)架構(gòu)中的單點故障
額外的網(wǎng)絡(luò)調(diào)用帶來的延遲增加
如果不進行擴展,它們很容易成為整個企業(yè)應(yīng)用的瓶頸。
額外的維護和開發(fā)費用
何時使用 API 網(wǎng)關(guān)
在復(fù)雜的微服務(wù)架構(gòu)中,它幾乎是必須的。
在大型企業(yè)中,API 網(wǎng)關(guān)是中心化安全性和橫切關(guān)注點的必要工具。
何時不宜使用 API 網(wǎng)關(guān)
在安全和集中管理不是最優(yōu)先要素的私人項目或小公司中。
如果微服務(wù)的數(shù)量相當(dāng)少。
可用技術(shù)示例
Amazon API 網(wǎng)關(guān), Azure API 管理, Apigee, Kong, WSO2 API 管理器
如果想在運行中的項目中使用微服務(wù)架構(gòu),我們需要將遺留的或現(xiàn)有的單體應(yīng)用遷移到微服務(wù)。將現(xiàn)有的大型在線單體應(yīng)用程序遷移到微服務(wù)是相當(dāng)有挑戰(zhàn)性的,因為這可能破壞應(yīng)用程序的可用性。
一個解決方案是使用 Strangler 模式。Strangler 模式意味著通過使用新的微服務(wù)逐步替換特定功能,將單體應(yīng)用程序增量地遷移到微服務(wù)架構(gòu)。此外,新功能只在微服務(wù)中添加,而不再添加到遺留的單體應(yīng)用中。然后配置一個 Facade (API 網(wǎng)關(guān))來路由遺留單體應(yīng)用和微服務(wù)間的請求。當(dāng)某個功能從單體應(yīng)用遷移到微服務(wù),F(xiàn)acade 就會攔截客戶端請求并路由到新的微服務(wù)。一旦遷移了所有的功能,遺留單體應(yīng)用程序就會被“扼殺(Strangler)”,即退役。

Md Kamaruzzaman 的 Strangler
優(yōu)點
安全的遷移單體應(yīng)用程序到微服務(wù)
可以并行地遷移已有功能和開發(fā)新功能
遷移過程可以更好把控節(jié)奏
缺點
在現(xiàn)有的單體應(yīng)用服務(wù)和新的微服務(wù)之間共享數(shù)據(jù)存儲變得具有挑戰(zhàn)性
添加 Facade (API 網(wǎng)關(guān))將增加系統(tǒng)延遲
端到端測試變得困難
何時使用 Strangler
將大型后端單體應(yīng)用程序的增量遷移到微服務(wù)
何時不宜使用 Strangler
如果后端單體應(yīng)用很小,那么全量替換會更好。
如果無法攔截客戶端對遺留的單體應(yīng)用程序的請求。
可用技術(shù)示例
API 網(wǎng)關(guān)后端應(yīng)用框架。
在微服務(wù)架構(gòu)中,微服務(wù)通過同步調(diào)用其他服務(wù)來滿足業(yè)務(wù)需求。服務(wù)調(diào)用會由于瞬時故障(網(wǎng)絡(luò)連接緩慢、超時或暫時不可用) 導(dǎo)致失敗,這種情況重試可以解決問題。然而,如果出現(xiàn)了嚴(yán)重問題(微服務(wù)完全失?。?,那么微服務(wù)將長時間不可用,這時重試沒有意義且浪費寶貴的資源(線程被阻塞,CPU 周期被浪費)。此外,一個服務(wù)的故障還會引發(fā)整個應(yīng)用系統(tǒng)的級聯(lián)故障。這時快速失敗是一種更好的方法。
在這種情況,可以使用斷路器模式挽救。一個微服務(wù)通過代理請求另一個微服務(wù),其工作原理類似于電氣斷路器,代理通過統(tǒng)計最近發(fā)生的故障數(shù)量,并使用它來決定是繼續(xù)請求還是簡單的直接返回異常。

Md Kamaruzzaman 的斷路器
斷路器可以有以下三種狀態(tài):
關(guān)閉:斷路器將請求路由到微服務(wù),并統(tǒng)計給定時段內(nèi)的故障數(shù)量,如果超過閾值,它就會觸發(fā)并進入打開狀態(tài)。
打開:來自微服務(wù)的請求會快速失敗并返回異常。在超時后,斷路器進入半開啟狀態(tài)。
半開:只有有限數(shù)量的微服務(wù)請求被允許通過并進行調(diào)用。如果這些請求成功,斷路器將進入閉合狀態(tài)。如果任何請求失敗,斷路器則會進入開啟狀態(tài)。
優(yōu)點
提高微服務(wù)架構(gòu)的容錯性和彈性
阻止引發(fā)其他微服務(wù)的級聯(lián)故障
缺點
需要復(fù)雜的異常處理
日志和監(jiān)控
應(yīng)該支持人工復(fù)位
何時使用斷路器
在微服務(wù)間使用同步通信的緊耦合的微服務(wù)架構(gòu)中
如果微服務(wù)依賴多個其他微服務(wù)
何時不宜使用斷路器
松耦合、事件驅(qū)動的微服務(wù)架構(gòu)
如果微服務(wù)不依賴于其他微服務(wù)
可用技術(shù)示例
API 網(wǎng)關(guān),服務(wù)網(wǎng)格,各種斷路器庫(Hystrix, Reselience4J, Polly)。
每個業(yè)務(wù)應(yīng)用都有許多用于各種基礎(chǔ)設(shè)施的配置參數(shù)(例如,數(shù)據(jù)庫、網(wǎng)絡(luò)、連接的服務(wù)地址、憑據(jù)、證書路徑)。此外在企業(yè)應(yīng)用程序通常部署在各種運行環(huán)境(Local、 Dev、 Prod)中,實現(xiàn)這些的一個方法是通過內(nèi)部配置。這是一個致命糟糕實踐,它會導(dǎo)致嚴(yán)重的安全風(fēng)險,因為生產(chǎn)憑證很容易遭到破壞。此外,配置參數(shù)的任何更改都需要重新構(gòu)建應(yīng)用程序,這在在微服務(wù)架構(gòu)中會更加嚴(yán)峻,因為我們可能擁有數(shù)百個服務(wù)。
更好的方法是將所有配置外部化,使得構(gòu)建過程與運行環(huán)境分離,生產(chǎn)的配置文件只在運行時或通過環(huán)境變量使用,從而最小化了安全風(fēng)險。
優(yōu)點
生產(chǎn)配置不屬于代碼庫,因而最小化了安全漏洞。
修改配置參數(shù)不需要重新構(gòu)建應(yīng)用程序。
缺點
我們需要選擇一個支持外部化配置的框架。
何時使用外部化配置
任何重要的生產(chǎn)應(yīng)用程序都必須使用外部化配置。
何時不宜使用外部化配置
在驗證概念的開發(fā)中。
可用技術(shù)示例
幾乎所有企業(yè)級的現(xiàn)代框架都支持外部化配置。
在微服務(wù)架構(gòu)中,通常有許多有不同團隊開發(fā)的微服務(wù)。這些微型服務(wù)協(xié)同工作來滿足業(yè)務(wù)需求(例如,客戶請求),并相互進行同步或異步通信。消費端微服務(wù)的集成測試具有挑戰(zhàn)性,通常用 TestDouble 以獲得更快、更低成本的測試運行。但是 TestDouble 通常并不能代表真正的微服務(wù)提供者,而且如果微服務(wù)提供者更改了它的 API 或 消息,那么 TestDouble 將無法確認(rèn)這些。另一種選擇是進行端到端測試,盡管它在生產(chǎn)之前是強制性的,但卻是脆弱的、緩慢的、昂貴的且不能替代集成測試(Test Pyramid)。
在這方面消費端驅(qū)動的契約測試可以幫助我們。在這里,負(fù)責(zé)消費端微服務(wù)的團隊針對特定的服務(wù)端微服務(wù),編寫一套包含了其請求和預(yù)期響應(yīng)(同步)或消息(異步)的測試套件,這些測試套件稱為顯式的約定。對于微服務(wù)服務(wù)端,將其消費端所有約定的測試套件都添加到其自動化測試中。當(dāng)特定服務(wù)端微服務(wù)的自動化測試執(zhí)行時,它將一起運行自己的測試和約定的測試并進行驗證。通過這種方式,契約測試可以自動的幫助維護微服務(wù)通信的完整性。
優(yōu)點
如果提供程序意外更改 API 或消息,可以被快速的自動發(fā)現(xiàn)。
更少意外、更健壯,特別是包含大量微服務(wù)的企業(yè)應(yīng)用程序。
改善團隊自主性。
缺點
需要額外的工作來開發(fā)和集成微服務(wù)服務(wù)端的契約測試,因為他們可能使用完全不同的測試工具。
如果契約測試與真實服務(wù)情況不匹配,將可能導(dǎo)致生產(chǎn)故障。
何時使用需求驅(qū)動的契約測試
在大型企業(yè)業(yè)務(wù)應(yīng)用程序中,通常由不同的團隊開發(fā)不同服務(wù)。
何時不宜使用消費端驅(qū)動的契約測試
所有微服務(wù)由同一團隊負(fù)責(zé)開發(fā)的小型簡單的應(yīng)用程序。
如果服務(wù)端微服務(wù)是相對穩(wěn)定的,并且不處在活躍的開發(fā)狀態(tài)。
可用技術(shù)示例
Pact, Postman, Spring Cloud Contract
在現(xiàn)代大規(guī)模企業(yè)軟件開發(fā)中,微服務(wù)架構(gòu)能夠幫助開發(fā)擴展規(guī)模并帶來很多長期收益。但是微服務(wù)架構(gòu)并不是隨處可用的銀彈,如果應(yīng)用在錯誤的應(yīng)用程序類型,微服務(wù)架構(gòu)將弊大于利。希望采用微服務(wù)架構(gòu)的開發(fā)團隊?wèi)?yīng)該遵循最佳實踐,并使用一系列可重用的、久經(jīng)錘煉的設(shè)計模式。
微服務(wù)架構(gòu)中至關(guān)重要的設(shè)計模式是獨享數(shù)據(jù)庫。實現(xiàn)這種設(shè)計模式具有挑戰(zhàn)性,需要其他幾種密切相關(guān)的設(shè)計模式(事件驅(qū)動、 CQRS、 Saga)來支持。在具有多個客戶端(Web、 Mobile、 Desktop、 Smart Devices)的典型業(yè)務(wù)應(yīng)用程序中,客戶端和微服務(wù)之間的通信量可能是很大的,并且需要統(tǒng)一的安全控制,在這種情況面向前端的后端和 API 網(wǎng)關(guān)的設(shè)計非常有用。此外,斷路器模式可以大大地幫助應(yīng)對這類應(yīng)用程序的錯誤處理場景。遷移遺留的單體應(yīng)用到微服務(wù)是極具挑戰(zhàn)性的,而 Strangler 模式可以幫助做到這點。消費端驅(qū)動的契約測試是微服務(wù)集成測試的基礎(chǔ)模式。另外外部化配置是任何現(xiàn)代化應(yīng)用程序開發(fā)中的一種必備模式。
這個系列并不全面,在實際情況中您可能需要其他的設(shè)計模式,但這個系列能為您提供一個關(guān)于微服務(wù)架構(gòu)設(shè)計模式的極好介紹。
原文鏈接:
https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41
- EOF -
PS:如果覺得我的分享不錯,歡迎大家隨手點贊、在看。 大家一起在評論區(qū)聊聊唄~
- EOF -
大家一起在評論區(qū)聊聊唄~
