天天看點

微服務的設計模式,你用了幾個微服務的設計模式,你用了幾個

微服務的設計模式,你用了幾個

微服務的設計模式,你用了幾個微服務的設計模式,你用了幾個

微服務架構已經成為現代應用開發的主流選擇。雖然它解決了某些問題,但它不是靈丹妙藥,也有幾個缺點。是以,需要讨論微服務的設計模式。

在深入研究設計模式之前,我們需要了解微服務架構的建構原則:

  1. 可擴充性
  2. 可用性
  3. 彈性
  4. 獨立、自主
  5. 去中心化治理
  6. 故障隔離
  7. 自動配置
  8. 通過 DevOps 持續傳遞

但是,應用所有這些原則會帶來一些挑戰和問題。接下來,讓我們讨論這些問題及其解決方案。

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 網關模式

當應用程式分解為較小的微服務時,需要解決一些問題:

  1. 如何調用多個微服務。
  2. 在不同的終端裝置(如PC、APP和Pad)上,因為 UI 不同,應用程式需要後端服務的不同資料,。
  3. 不同的消費者可能需要不同格式的響應資料。誰将進行資料轉換或字段操作?
  4. 如何處理不同類型的協定。

API 網關有助于解決微服務實作帶來的許多問題:

  1. API 網關是任何微服務調用的單一入口點。
  2. 它可以作為代理服務将請求路由到相關的微服務。
  3. 它可以将請求發送到多個服務并彙總結果以發回給請求者。
  4. 一刀切的 API 無法解決消費者的所有需求;此解決方案可以為每種特定類型的用戶端建立細粒度的 API。
  5. 它還可以将請求協定(例如 AMQP)轉換為另一種協定(例如 HTTP),反之亦然。
  6. 它還可以對不同的微服務,建立統一的身份驗證/授權。

b. 聚合器模式

我們已經讨論了解決 API 網關模式中的聚合資料問題。但是,我們将在這裡全面讨論它。當将業務功能分解為幾個較小的代碼段時,有必要考慮如何聚合每個服務傳回的資料。這個責任不能留給消費者,因為它可能需要了解生産者的内部實作。

聚合器模式有助于解決這個問題。它可以聚合來自不同服務的資料,然後再發送給消費者。這可以通過兩種方式完成:

  1. 複合微服務:将調用所有需要的微服務,合并資料,并在應答之前轉換資料。
  2. API 網關: 還可以将請求劃分為多個微服務,并在将資料發送給消費者之前聚合資料。

如果還要處理業務邏輯,建議選擇複合微服務。

c. 用戶端組合模式

當通過分解業務能力/子域來開發服務時,用戶端必須從多個微服務中拉取資料。在單體世界中,用戶端一般隻需要調用一次後端服務來查詢或重新整理所有資料。然而,現在情況将不一樣了,我們需要了解如何去做。

對于微服務,用戶端可能需要設計為具有多個部分/區域的骨架。每個部分都會調用一個單獨的後端微服務來拉取資料。這稱為單頁應用程式 (Single Page Applications,SPA),像 AngularJS 和 ReactJS 這樣的架構有助于輕松地做到這一點。在需要重新整理時,應用程式能夠刷特定區域而不是整個頁面。

3. 資料庫模式

a. 每個服務的資料庫

如何定義微服務的資料庫架構也是一個問題:

  1. 服務必須是松耦合的。它們可以獨立開發、部署和擴充。
  2. 業務請求處理可能會跨越多個服務。
  3. 一些事務需要查詢多個服務擁有的資料。
  4. 資料庫有時必須被複制和分片才能擴充。
  5. 不同的服務有不同的資料存儲要求。

為了解決上述問題,每個微服務必須設計一個資料庫,它必須僅供該服務專用。它也應該隻能通過微服務 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 代表一個進階業務流程,它由多個子請求組成,每個子請求都更新單個服務中的資料。每個請求都有一個補償請求,在請求失敗時執行。

它可以通過兩種方式實作:

  1. 事件編排 (Event Choreography):沒有中央協調器(沒有單點風險)時,每個服務産生并觀察其他服務的事件,并決定是否應采取行動。
  2. 指令協調(Order Orchestrator):中央協調器負責集中處理事件的決策和業務邏輯排序。。

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. 跨領域關注模式

a. 外部配置

服務通常也調用其他服務和資料庫。對于每個環境,如 dev、QA、UAT、prod,某些配置屬性可能不同。任何這些屬性的更改都可能需要重新建構和重新部署服務。我們如何避免因配置更改而修改代碼?

外部化所有配置,包括憑據。應用程式應在啟動時動态加載它們。

Spring Cloud 配置伺服器提供了将屬性外部化到 GitHub 并将它們作為環境屬性加載的選項。這些可以在啟動時由應用程式通路,也可以在不重新啟動伺服器的情況下重新整理。

b. 服務發現模式

當微服務出現後,我們需要解決服務調用方面的幾個問題:

  1. 使用容器技術,IP 位址被動态配置設定給服務執行個體。每次位址更改時,消費者服務都可能中斷并需要手動更改。
  2. 每個服務 URL 都必須被消費者記住并緊密耦合。

那麼消費者或路由器如何知道所有可用的服務執行個體和位置呢?

需要建立一個服務注冊中心來儲存每個生産者服務的中繼資料。服務執行個體應在啟動時注冊到系統資料庫,并在停止時取消注冊。消費者或路由器應查詢系統資料庫并找出服務的位置。注冊中心還需要對生産者服務進行健康檢查,以確定隻有服務的工作執行個體可供通過它使用。有兩種類型的服務發現:用戶端和伺服器端。

服務發現(用戶端)的一個例子是 Netflix Eureka,服務發現(伺服器端)的一個例子是 AWS ALB。

c. 斷路器模式

一個服務一般會調用其他服務來查詢資料,但下遊服務有可能當機。這樣做有兩個問題:第一,請求會一直到當機的服務,耗盡網絡資源,降低性能。其次,使用者體驗會很差且不可預測。我們如何避免級聯服務故障并優雅地處理故障?

消費者應該通過代理調用遠端服務,該代理的行為方式與電路斷路器類似。當連續失敗次數超過門檻值時,斷路器跳閘,并且在逾時期限内,所有調用遠端服務的嘗試都将立即失敗。逾時到期後,斷路器允許有限數量的測試請求通過。如果這些請求成功,斷路器将恢複正常操作。否則,如果出現故障,逾時時間将重新開始。

Netflix Hystrix 是斷路器模式的一個很好的實作。它還可以在斷路器跳閘時使用回退機制。這提供了更好的使用者體驗。

d. 藍綠部署模式

使用微服務架構,一個應用可以有多個微服務。如果我們停止所有服務,然後部署心版本,停機時間将會非常長,并且會影響業務。此外,復原将是一場噩夢。我們如何避免或減少部署期間服務的停機時間?

可以實施藍綠部署政策以減少或消除停機時間。它通過運作兩個相同的生産環境 Blue 和 Green 來實作這一點。讓我們假設 Green 是現有的實時執行個體,而 Blue 是應用程式的新版本。在任何時候,隻有一個環境處于活動狀态,實時環境服務于所有生産流量。幾乎所有雲平台都提供了實施藍綠部署的選項。

還有許多其他與微服務架構一起使用的模式,如 Sidecar、鍊式微服務、分支微服務、事件溯源模式、持續傳遞模式等。如果你還知道其他的微服務模式,歡迎留言交流。

參考連結:

https://dzone.com/articles/design-patterns-for-microservices