微服务的设计模式,你用了几个
目錄
1. 分解模式
a. 按業務能力分解
b. 按子域分解
c. 扼殺者模式
2. 集成模式
a. API 網關模式
b. 聚合器模式
c. 客戶端組合模式
3. 數據庫模式
a. 每個服務的數據庫
b. 共享數據庫
c. 命令查詢職責分離 (CQRS)
d. Saga模式
4. 可觀察性模式
a. 日志聚合
b. 性能指標
c. 分布式追蹤
d. 健康檢查
5. 跨領域關注模式(Cross-Cutting Concern)
a. 外部配置
b. 服務發現模式
c. 斷路器模式
d. 藍綠部署模式
?微服務架構已經成為現代應用開發的主流選擇。雖然它解決了某些問題,但它不是靈丹妙藥,也有幾個缺點。因此,我們需要討論微服務的設計模式,幫助我們解決一些問題。
在深入研究設計模式之前,我們需要了解微服務的構建原則:
但是,應用所有這些原則會帶來一些挑戰和問題。接下來,讓我們討論這些問題及其解決方案。
1. 分解模式
a. 按業務能力分解
問題
微服務的目標之一是讓服務松散耦合,應用單一職責原則。但是,將應用程序分解成更小的部分必須符合邏輯。我們如何將應用程序分解為小服務?
解決方案
一種策略是按業務能力分解----業務能力是企業為了創造價值而做的事情,給定業務的能力集取決于業務類型。例如,保險公司的能力通常包括銷售、營銷、承保、理賠處理、計費等。每個業務能力都可以被認為是一種服務。
b. 按子域分解
問題
使用業務能力分解應用程序可能是一個好的開始,但你會遇到所謂的“上帝類(God Classes)”,它并不容易分解。這些類將在多個服務中通用。例如,Order 類將用于訂單管理、接單、訂單交付等,我們如何分解它們?
備注:
”去除上帝類”是指把一個看似功能很強且很難維護的類,按照職責把自己的屬性或方法分派到各自的類中或分解成功能明確的類,從而去掉上帝類。
解決方案
對于“God Classes”問題,可以通過DDD(領域驅動設計)來拯救。它使用子域和有界上下文概念來解決這個問題。DDD 將為企業創建的整個域模型分解為子域,每個子域都有一個模型,該模型的范圍將稱為有界上下文。每個微服務都將圍繞有界上下文開發。
注意:識別子域并非易事。它需要對業務的了解。與業務能力一樣,子域是通過分析業務及其組織結構并確定不同的專業領域來確定的。
c. 扼殺者模式
問題
到目前為止,我們討論的設計模式是分解綠地應用程序(Greenfield),但我們所做的 80% 的工作是處理棕地應用程序(Brownfield),它們是大型的單體應用程序。將上述所有設計模式應用于它們將很困難,因為把它們分解成更小的部分是一項艱巨的任務。
備注:
綠地應用程序(Greenfield)
即一個新項目,從頭開始一個新的軟件項目。類比是在綠地上施工,無需改造或拆除現有結構。
(來自http://en.wikipedia.org/wiki/Greenfield_project)
棕地應用程序(Brownfield)
Brownfield開發是IT行業中常用的術語,用于描述現有結構首先需要拆除的網站,即在現有軟件項目中構建。
(來自http://en.wikipedia.org/wiki/Brownfield_(software_development))
解決方案
這就需要扼殺者模式(Strangler)來拯救。
扼殺者模式是基于一個藤蔓扼殺它所纏繞的樹的類比。此解決方案適用于 Web 應用程序,可以將服務分解為不同的域并作為單獨的服務托管。一次做一個域,這將創建兩個獨立的應用程序,它們并排在同一個 URI 空間中。最終,新重構的應用程序“扼殺”或替換原始應用程序,直到你最終可以放棄傳統的單體應用程序。
[澳大利亞]地區的自然奇觀之一是巨大的扼殺者藤蔓。 他們在無花果樹的樹枝上播種,并逐漸沿著樹下工作,直到扎根在土壤中。 多年來,它們長成奇妙而美麗的形狀,同時勒死并殺死了作為寄主的樹。
2. 集成模式
a. API 網關模式
問題
當應用程序分解為較小的微服務時,需要解決一些問題:
解決方案
API 網關有助于解決微服務帶來的許多問題:
b. 聚合器模式
問題
我們已經討論了解決 API 網關模式中的聚合數據問題。但是,我們將在這里全面討論它。當將業務功能分解為幾個較小的代碼段時,有必要考慮如何聚合每個服務返回的數據。這個責任不能留給消費者,因為它可能需要了解生產者的內部實現。
解決方案
聚合器模式有助于解決這個問題。它可以聚合來自不同服務的數據,然后再發送給消費者。這可以通過兩種方式完成:
如果還要處理業務邏輯,建議選擇復合微服務。
c. 客戶端組合模式
問題
當通過分解業務能力/子域來開發服務時,客戶端必須從多個微服務中拉取數據。在單體世界中,客戶端一般只需要調用一次后端服務來查詢或刷新所有數據。然而,現在情況將不一樣了,我們需要了解如何去做。
解決方案
對于微服務,客戶端可能需要設計為具有多個部分/區域的骨架。每個部分都會調用一個單獨的后端微服務來拉取數據。這稱為單頁應用程序 (Single Page Applications,SPA),像 AngularJS 和 ReactJS 這樣的框架有助于輕松地做到這一點。在需要刷新時,應用程序能夠刷特定區域而不是整個頁面。
3. 數據庫模式
a. 每個服務的數據庫
問題
如何定義微服務的數據庫架構也是一個問題:
解決方案
為了解決上述問題,每個微服務必須設計一個數據庫,它必須僅供該服務專用。它也應該只能通過微服務 API 訪問,而不能被其他服務直接訪問。例如,對于關系數據庫,我們可以使用 private-tables-per-service、schema-per-service 或 database-server-per-service。每個微服務都應該有一個單獨的數據庫 id,以便可以給予單獨的訪問權限,并防止它使用其他服務表。
備注:
Private-tables-per-service——每一服務擁有一系列只能被該服務訪問的表
Schema-per-service——每一服務擁有一個為該服務所私有的數據庫Schema
Database-server-per-service——每一服務擁有自己的數據庫
b. 共享數據庫
問題
每個服務一個數據庫是微服務的理想選擇。當應用程序是全新的并且要使用 DDD 開發時,這是可能的。但是,如果應用程序是單體應用程序并試圖改進為微服務架構,那么就不是那么容易了。在這種情況下,合適的架構是什么?
解決方案
共享數據庫并不理想,但這是上述場景的解決方案。大多數人認為這是微服務的反模式,但對于棕地應用程序,這是將應用程序分解為更小部分的良好開端。在這種模式中,一個數據庫可以供多個微服務調用,但最多只能限制在 2-3 個,否則擴展性、自治性和獨立性將難以執行。
c. 命令查詢職責分離 (CQRS)
問題
一旦我們實現了每個服務的數據庫,就需要查詢。那么,對于來自多個服務的聯合數據,我們如何在微服務架構中實現查詢呢?
解決方案
CQRS 建議將應用程序分成兩部分——命令端和查詢端。
CQRS 將系統中的操作分為兩類,即「命令」(Command) 與「查詢」(Query)。命令則是對會引起數據發生變化操作的總稱,即我們常說的新增,更新,刪除這些操作,都是命令。而查詢則和字面意思一樣,即不會對數據產生變化的操作,只是按照某些條件查找數據。
查詢端使用物化視圖處理查詢部分。視圖會被保存在訂閱了事件的服務中,每個服務在更新數據時會發布出這些事件。例如,網店可以通過維護一個客戶信息和訂單信息的Join視圖來查詢特定區域客戶和他們的近期訂單。該視圖由訂閱了客戶信息事件和訂單信息事件的服務進行更新。
d. Saga模式
問題
當每個服務都有自己的數據庫,一個請求事務跨越多個服務時,我們如何保證跨服務的數據一致性呢?例如,對于電子商務應用程序,應用程序必須確保新訂單不會超過客戶的信用額度。由于 Orders 和 Customers 位于不同的數據庫中,因此應用程序不能簡單地使用本地 ACID 事務。
解決方案
Saga 代表一個高級業務流程,它由多個子請求組成,每個子請求都更新單個服務中的數據。每個請求都有一個補償請求,在請求失敗時執行。
它可以通過兩種方式實現:
4. 可觀察性模式
a. 日志聚合
問題
考慮一個用例,其中應用程序由在多臺機器上運行的多個服務實例組成。請求通常跨越多個服務實例,每個服務實例都會生成一個標準化格式的日志文件,我們如何通過日志了解特定請求的應用程序行為?
解決方案
我們需要一個集中的日志服務來聚合來自每個服務實例的日志。用戶可以搜索和分析日志,還可以在日志中配置出現某些消息時觸發的警報。例如,PCF 確實有 Loggeregator,它從 PCF 平臺的每個組件(路由器、控制器、diego 等)以及應用程序收集日志。AWS Cloud Watch 也有同樣的作用。
b. 性能指標
問題
當服務數量不斷增加時,密切關注應用性能變得至關重要,以便可以出現問題時發送警報。我們應該如何收集指標來監控應用程序性能?
解決方案
需要度量服務來收集有關單個操作的統計信息。有兩種聚合指標的模型:
- Push — 服務將指標推送到指標服務,例如 NewRelic、AppDynamics、Prometheus
- Pull — 指標服務從服務中提取指標,例如 Prometheus
c. 分布式追蹤
問題
在微服務架構中,請求通常跨越多個服務。那么,我們如何跟蹤一個請求來排查問題呢?
解決方案
我們需要一項服務
- 為每個外部請求分配一個唯一的外部請求 ID。
- 將外部請求 ID 傳遞給所有服務。
- 在所有日志消息中包含外部請求 ID。
- 集中式記錄和處理外部請求執行時操作的信息。
Spring Cloud Slueth 和 Zipkin 服務器是一類常見的實現。
d. 健康檢查
問題
實施微服務架構后,有可能遇到服務已啟動但無法處理請求的問題。在這種情況下,你如何確保請求不會發送到那些失敗的實例?
解決方案
每個服務都需要有一個端點,可用于檢查應用程序的健康狀況,例如 /health, 此 API 應檢查主機的狀態、與其他服務/基礎設施的連接以及任何特定邏輯。
Spring Boot Actuator 實現了一個/health 端點,并且該實現也可以自定義。
5. 跨領域關注模式(Cross-Cutting Concern)
“cross-cutting concerns”指的是兩個非常不一樣的組件存在一些類似的功能。
a. 外部配置
問題
服務通常也調用其他服務和數據庫。對于每個環境,如 dev、QA、UAT、prod,某些配置屬性可能不同。任何這些屬性的更改都可能需要重新構建和重新部署服務。我們如何避免因配置更改而修改代碼?
解決方案
外部化所有配置,包括憑據。應用程序應在啟動時動態加載它們。
Spring Cloud 配置服務器提供了將屬性外部化到 GitHub 并將它們作為環境屬性加載的選項。這些可以在啟動時由應用程序訪問,也可以在不重新啟動服務器的情況下刷新。
b. 服務發現模式
問題
當微服務出現后,我們需要解決服務調用方面的幾個問題:
那么消費者或路由器如何知道所有可用的服務實例和位置呢?
解決方案
需要創建一個服務注冊中心來保存每個生產者服務的元數據。服務實例應在啟動時注冊到注冊表,并在停止時取消注冊。消費者或路由器應查詢注冊表并找出服務的位置。注冊中心還需要對生產者服務進行健康檢查,以確保只有服務的工作實例可供通過它使用。有兩種類型的服務發現:客戶端和服務器端。
服務發現(客戶端)的一個例子是 Netflix Eureka,服務發現(服務器端)的一個例子是 AWS ALB。
c. 斷路器模式
問題
一個服務一般會調用其他服務來查詢數據,但下游服務有可能宕機。這樣做有兩個問題:第一,請求會一直到宕機的服務,耗盡網絡資源,降低性能。其次,用戶體驗會很差且不可預測。我們如何避免級聯服務故障并優雅地處理故障呢?
解決方案
消費者應該通過代理調用遠程服務,該代理的行為方式與電路斷路器類似。當連續失敗次數超過閾值時,斷路器跳閘,并且在超時期限內,所有調用遠程服務的嘗試都將立即失敗。超時到期后,斷路器允許有限數量的測試請求通過。如果這些請求成功,斷路器將恢復正常操作。否則,如果出現故障,超時時間將重新開始。
Netflix Hystrix 是斷路器模式的一個很好的實現。它還可以在斷路器跳閘時使用回退機制。這提供了更好的用戶體驗。
d. 藍綠部署模式
問題
使用微服務架構,一個應用可以有多個微服務。如果我們停止所有服務,然后部署新版本,停機時間將會非常長,并且會影響業務。此外,回滾將是一場噩夢。我們如何避免或減少部署期間服務的停機時間?
解決方案
可以實施藍綠部署策略以減少或消除停機時間。它通過運行兩個相同的生產環境 Blue 和 Green 來實現這一點。讓我們假設 Green 是現有的實時實例,而 Blue 是應用程序的新版本。在任何時候,只有一個環境處于活動狀態,實時環境服務于所有生產流量。幾乎所有云平臺都提供了實施藍綠部署的選項。
還有許多其他與微服務架構一起使用的模式,如 Sidecar、鏈式微服務、分支微服務、事件溯源模式、持續交付模式等。如果你還知道其他的微服務模式,歡迎留言交流。
參考鏈接: https://dzone.com/articles/design-patterns-for-microservices
總結
以上是生活随笔為你收集整理的微服务的设计模式,你用了几个的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二层数据帧转发过程
- 下一篇: json文件批量转换xml