微服務設計模式是一種指導微服務架構設計和開發的一系列原則和實踐。微服務設計模式的目的是為了解決微服務架構中遇到的一些常見的問題和挑戰,比如服務劃分、服務通信、服務治理、服務測試等。微服務設計模式可以幫助我們構建出高效、可靠、可擴展、可維護的微服務系統。
本文將介紹以下十種微服務設計模式:
-
API 網關(Api Gateway Pattern)
-
服務發現與注冊(Service Registration and Discovery Pattern)
-
斷路器(Circuit Breaker Pattern)
-
隔板模式(Bulkhead Pattern)
-
命令和查詢職責分離(CQRS Pattern)
-
事件驅動模式(Dvent Driven Pattern)
-
Saga 模式(Saga Pattern)
-
扼殺者模式(Strangler Pattern)
-
邊車模式(Sidecar Pattern)
-
BFF 模式(Backend for Frontend Pattern)
1. API 網關
API 網關是訪問任何微服務的入口點,位于客戶端和微服務之間,負責處理諸如鑒權、限流、重試、負載均衡、服務發現等通用功能,以及根據客戶端的需求進行數據過濾、映射和聚合等操作。這種模式可以簡化客戶端的邏輯,減少網絡開銷,保護后端服務,以及實現不同級別的 API 接口。在 Spring Cloud 中我們可以使用 Zuul 或 Spring Cloud Gateway 來實現這一點。
應用場景
-
對于任何微服務調用 API 網關是唯一入口,簡化客戶端邏輯。
-
可以根據不同的規則將請求路由到不同的微服務上。
-
可以與 Eureka、Nacos、Ribbon 等注冊中心集成,實現服務發現和負載均衡。
-
可以聚合后端的請求結果再發送給前端。
-
可以在不同通信協議的服務之間做協議轉換。
-
可以把授權/認證功能從微服務中遷移到 API 網關上。
-
可以記錄請求日志。
-
可以做服務限流以及服務熔斷。
2. 服務注冊與發現
服務注冊與發現是一種用于管理微服務實例地址變化的技術。它可以讓微服務之間通過一個統一的服務名來進行通信,而不需要知道對方的具體位置。它主要包括兩個組件:服務注冊中心和服務發現客戶端。
-
服務注冊中心:服務注冊中心是一個中心化的組件,負責存儲所有微服務實例的位置信息(如 IP 地址和端口號),以及提供查詢和更新這些信息的接口。每個微服務實例在啟動時都會向服務注冊中心注冊自己的位置信息,并定期發送心跳消息來維持自己的在線狀態。如果某個微服務實例停止或下線了,它會從服務注冊中心注銷自己的位置信息,或者由服務注冊中心檢測到并刪除它。
-
服務發現客戶端:服務發現客戶端是一個分布式的組件,負責從服務注冊中心獲取所需微服務實例的位置信息,并根據負載均衡策略選擇一個合適的實例進行調用。每個客戶端或其他微服務在需要調用某個微服務時都會使用其服務名來請求服務發現客戶端,由服務發現客戶端返回一個可用的實例地址,并建立連接。
引入服務注冊與發現可以給微服務架構帶來很多好處,例如,
-
動態發現:我們可以動態地發現新加入或退出的微服務實例,而不需要手動配置或修改地址信息。
-
負載均衡:我們可以根據不同的算法(如輪詢、隨機、最少連接等)來選擇最合適的微服務實例來處理請求,從而提高系統的性能和效率。
-
容錯處理:我們可以檢測并排除不可用或故障的微服務實例,從而提高系統的可靠性和穩定性。
常見的服務注冊中心如下,
-
Eureka:Eureka 是 Netflix 開源的一款服務發現組件,是 Spring Cloud 老版本的核心組件之一,現在已經處于維護期。它提供了服務注冊、服務發現和負載均衡等功能,具有高可用、高可靠、易于擴展的特點。適用于需要高可用、易于部署和維護的微服務架構。
-
Consul:Consul 是由 HashiCorp 開源的一款服務網格解決方案,提供了服務注冊、服務發現和健康檢查等功能,同時還支持多數據中心部署和分布式一致性協議。適用于需要多數據中心部署和強一致性的微服務架構。
-
Zookeeper:Zookeeper 是 Apache 開源的一款分布式協調服務,提供了命名服務、配置管理、分布式鎖等功能。Zookeeper 具有高可用、高可靠、支持集群和多數據中心等特點。適用于需要分布式鎖、分布式配置管理等功能的微服務架構。
-
Nacos:Nacos 是阿里巴巴開源的一款動態服務發現、配置管理和服務管理平臺,支持 DNS-based 和 RPC-based 兩種模式。Nacos 具有簡單易用、高性能、高可擴展等特點。適用于需要動態配置管理和服務治理的微服務架構。
-
Etcd:Etcd 是一個分布式鍵值存儲系統,基于 Raft 協議實現了強一致性和容錯性。Etcd 可以作為服務注冊中心使用,也可以作為配置中心或分布式鎖等其他場景使用。適用于需要強一致性和高性能的微服務架構。
3. 斷路器
斷路器是一種處理遠程調用失敗或超時的模式。由于微服務之間需要通過網絡進行通信,因此可能會遇到網絡故障、超時、擁塞等問題,導致遠程調用失敗或延遲。如果不及時處理這些問題,可能會造成雪崩效應(Cascading Failure),即一個失敗的調用會引起其他調用的失敗,最終導致整個系統崩潰。電路斷路器模式可以避免這種情況,它類似于電路中的保險絲,當檢測到某個遠程調用出現故障時,就會切斷該調用,防止進一步的損害,并嘗試恢復該調用。在 Spring Cloud 中,我們可以使用 Hystrix 或 Resilient4J 來實現斷路器。
斷路器模式通常有三種狀態:閉合(Closed)、打開(Open)和半開(Half-Open)。閉合狀態表示遠程調用正常工作,打開狀態表示遠程調用出現故障,半開狀態表示遠程調用正在恢復。電路斷路器根據一定的條件和策略來切換這三種狀態,比如故障次數、故障比例、故障時間等。電路斷路器還可以提供一些備選方案來處理失敗的調用,比如重試、降級、緩存等。
斷路器行為類似于電路中的斷路器。當連續的請求失敗的次數超過閾值時,斷路器將跳閘一段時間,并且在跳閘的這段時間內,所有遠程服務調用的嘗試都將立即失敗。當超過了斷路器跳閘時間之后,斷路器將允許有限數量的測試請求通過。如果這些請求成功,則斷路器將恢復正常操作。否則如果有一個請求失敗,則斷路器再次跳閘。對于一個應用試圖嘗試調用另一個遠程服務或者獲取共享資源,并且該操作很容易的失敗的情況來說, 這個模式非常適用。
3. 隔板模式
隔板模式(Bulkhead Pattern)通過根據需要調用的服務數量劃分線程池,幫助處理與線程池相關的容錯問題。例如我們在服務 A 中定義了一個 50 線程池,服務 A 會向服務 B 和 C 發出請求。因此服務 A 應該將 50 線程池分為 2 個(服務 B 25 個,服務 C 25 個),如果服務 C 不可用或需要較長時間來處理請求,則不會影響服務 B 調用,因為它有自己的線程池來執行作業。在 Spring Cloud 中,我們可以使用 Resilient4J 來實現這一點。
隔板模式類似于船體中一個個被隔離的分區。根據使用者負載和可用性要求,這些分區服務實例被分割到不同的組里面。這種設計模式有助于隔離故障(isolate failures), 并允許即使在故障期間仍可為某些使用者提供服務功能。
5. 命令和查詢職責分離
命令和查詢職責分離(Command Query Responsibility Segregation,CQRS)模式,是一種將數據存儲的讀取操作和更新操作分離的模式。這種模式的目的是提高微服務的性能、可擴展性和安全性。CQRS 的基本思想是,對于不同的操作,可以使用不同的模型、服務和數據庫。例如,讀取操作可以使用一個優化了查詢效率的數據庫,而更新操作可以使用一個保證了數據一致性的數據庫。這樣就可以根據不同的需求來選擇合適的技術和架構。
優點
-
可以根據讀寫比例來調整資源分配,提高系統的效率和響應速度。
-
可以針對不同的場景使用不同的數據模型和驗證規則,提高系統的靈活性和可維護性。
-
可以降低數據沖突和并發問題的風險,提高系統的可靠性和安全性。
缺點
-
需要維護多個數據源之間的同步和一致性,增加了系統的復雜度和開發成本。
-
需要處理數據延遲和最終一致性的問題,可能影響用戶體驗和業務邏輯。
6. 事件驅動模式
微服務中的事件驅動模式是一種讓微服務之間通過發布和訂閱事件來進行異步通信的模式。事件是一種表示系統中發生了某種變化或動作的消息,比如訂單創建、支付完成、用戶注冊等。事件驅動模式的優點是可以降低微服務之間的耦合度,提高系統的可擴展性、性能和可靠性,以及支持復雜的業務邏輯和流程。事件驅動模式的挑戰是需要保證事件的順序、一致性、冪等性和可追溯性,以及處理分布式事務和異常情況。事件驅動模式中的事件一般是通過消息隊列發出,例如 RabbitMQ 或 Apache Kafka。
事件驅動模式讓微服務之間通過發布和訂閱事件來進行異步通信,而不是直接調用或依賴其他微服務的接口。這樣每個微服務只需要關注自己的業務邏輯,而不需要知道其他微服務的存在和狀態。
7. Saga 模式
眾所周知,處理分布式系統很困難,尤其是涉及分布式事務時,二階段提交是最好的選擇,但由于其悲觀鎖的性質使其難以擴展、性能較低,所以就有了 Saga 模式,是一種在分布式事務場景中跨微服務管理數據一致性的方法。Saga 是一系列事務,用于更新每項服務并發布消息或事件來觸發下一個事務步驟。如果某個步驟失敗,則 Saga 將執行補償事務,以抵消上一個事務的影響。這種模式可以保證數據的最終一致性,同時避免了長時間鎖定資源的問題。有兩種常見的 Saga 實現方法,即協調和編排。 每個方法都有自己的一組挑戰和技術來協調工作流。
協調
協調是協調 Saga 的一種方法,參與者在沒有集中控制點的情況下交換事件。 通過協調,每個本地事務都會發布在其他服務中觸發本地事務的域事件。。
好處
-
適用于只需很少參與者且不需要協調邏輯的簡單工作流。
-
不需要額外的服務實現和維護。
-
不會引入單一故障點,因為責任在各個 Saga 參與者之間進行分配。
缺點
-
添加新步驟時,工作流可能會變得混亂,因為很難跟蹤哪些 Saga 參與者偵聽哪些命令。
-
由于 Saga 參與者必須使用彼此的命令,因此他們之間存在循環依賴的風險。
-
集成測試很困難,因為必須運行所有服務才能模擬事務。
編排
編排是協調 Saga 的一種方法,在此方法中,中央控制器告訴 Saga 參與者要執行的本地事務。 Saga 編排器處理所有事務,并告知參與者根據事件執行哪項操作。 編排器執行 Saga 請求、存儲和解釋每個任務的狀態,并通過補償事務處理故障恢復。
好處
-
適用于只需很少參與者且不需要協調邏輯的簡單工作流。
-
不需要額外的服務實現和維護。
-
不會引入單一故障點,因為責任在各個 Saga 參與者之間進行分配。
缺點
-
添加新步驟時,工作流可能會變得混亂,因為很難跟蹤哪些 Saga 參與者偵聽哪些命令。
-
由于 Saga 參與者必須使用彼此的命令,因此他們之間存在循環依賴的風險。
-
集成測試很困難,因為必須運行所有服務才能模擬事務。
8. 扼殺者模式
扼殺者(Strangler Pattern)模式是一種將單體應用逐漸遷移到微服務架構的模式,它的靈感來源于一種纏繞并殺死它所依附的樹木的藤蔓植物。扼殺者模式的基本思想是,通過創建單體應用的新版本來替換舊版本,同時保持外部 API 不變,讓客戶端感知不到任何變化。隨著轉換進度的推進,最終所有功能都被重構為微服務,新架構“扼殺”取代了原來的單體架構。
扼殺應用(Strangler Application)的步驟分為轉換,共存和消滅三步:
-
轉換(Transform?) —? 用新方式創建一個新的平行的服務。
-
共存(Coexist?)—? 保持老服務,將老服務請求重定向到新服務,新服務逐步實現老服務的功能。
-
消滅(Eliminate?) —? 移除老服務。
扼殺者模式的優點是可以漸進地進行微服務化,而不是一次性地重寫整個應用,這樣可以降低風險和成本,同時保持業務的連續性和穩定性。缺點是需要維護兩套系統之間的兼容性和同步性,這可能會增加系統的復雜度和開發成本。
9. 邊車模式
邊車模式(Sidecar Pattern)是一種將一些與業務邏輯無關的功能(如日志、監控、配置、安全等)從主應用程序中分離出來,部署在同一個主機或容器中的一個獨立的進程或服務中的模式。這樣,主應用程序可以專注于自己的核心功能,而邊車服務可以提供一些通用的功能,比如數據轉換、網絡通信、故障處理等。邊車服務與主應用程序之間通過本地接口或共享內存來進行通信,從而實現高效和透明的協作。
邊車模式的優點是可以降低微服務之間的耦合度,提高微服務的性能、可靠性和靈活性,以及簡化微服務的開發和維護。缺點是需要額外的資源和管理成本,以及處理邊車與主應用程序之間的通信和協調問題。
10. BFF 模式
BFF 模式是一種為前端定制的后端的模式,它的全稱是 Backend for Frontend。BFF 模式的目的是將后端的微服務根據不同的前端渠道和場景進行適配和聚合,提供給前端友好和統一的 API,從而提升前端的用戶體驗和開發效率。BFF 模式可以讓前端與后端之間實現更好地解耦和協作。
BFF 模式的優點是可以根據不同的前端需求來定制和優化 API,避免了過度抽象或者冗余的 API,提高了網絡傳輸和數據處理的效率。缺點是需要額外的開發和維護成本,每個前端渠道都需要一個對應的 BFF,可能會導致代碼重復或者不一致。
應用場景
-
接口剪裁:后端提供的一個接口,對于不同的前端場景來說,需求的字段可能會不同。BFF 的剪裁能力使得后端只需要專注領域開發,不需要為前端定制不同的 API 接口,方便 API 生命周期的管理。
-
接口聚合:一個前端頁面,往往會依賴多個后端接口,這樣就需要和后端產生多次交互。BFF 可以對后端接口進行聚合,并處理依賴關系,使得前端一個頁面只需要和后端交互一次。
總結
以上的十種設計模式能幫助我們構建擴展性良好的軟件系統,但是在生產實踐中,我們還需要根據具體的業務場景和需求來引入合適的微服務設計模式。
最后感謝大家閱讀,希望本文能對你有所幫助.
關注公眾號【waynblog】每周分享技術干貨、開源項目、實戰經驗、高效開發工具等,您的關注將是我的更新動力!