微服務架構及設計模式

【導讀】微服務架構設計上有多少通用模式?本文總結了常見的爲服務設計模式並進行了解讀。

本文介紹了主流常見的微服務模式。

微服務能夠對企業產生積極影響。因此,瞭解如何處理微服務架構(MSA)以及一些微服務設計模式,一個微服務架構的一些通用目標或者設計原則是很有價值的。下面是在微服務架構方案中值得考慮的四個目標。

1、縮減成本:MSA 將會降低設計、實現和維護 IT 服務的總體成本

2、加快發佈速度:MSA 將會加快服務從想法到部署的落地速度

3、增強彈性:MSA 將會提升我們服務網絡的彈性

4、開啓可見性:MSA 支持爲服務和網絡提供更好的可見性

你需要了解建設微服務架構背後的幾個設計原則:

聽取上述原則,在你實施的解決方案或系統付諸實踐的同時,這也會帶來一些挑戰和問題。這些問題在許多解決方案中也很常見。使用正確及匹配的設計模式可以克服這些問題。微服務有一些設計模式,這可以大體分爲五類。每類都包含許多具體的設計模式。下圖展示了這些設計模式。

分解模式

按業務功能進行分解

說白了,微服務就是要應用單一職責原則,把服務改造成松耦合式的。它可以按照業務功能進行分解。定義和業務功能相對應的服務。業務功能是一個來自業務架構建模的概念。它是一個企業爲了創造價值而要去做的某些事情。一個業務功能往往對應於一個業務對象,比如:

按問題子域進行分解

按照業務功能來分解一個應用程序可能會是一個不錯的開始,但是你終將會遇到所謂的 “神類”,它很難再被分解。這些類將在多個服務之間都是通用的。可以定義一些和領域驅動設計(DDD)裏面的子域相對應的服務。DDD 把應用程序的問題空間 —— 也即是業務 —— 稱之爲域。一個域由多個子域組成。每個子域對應業務的各個不同部分。

子域可以分爲如下幾類:

一個訂單管理的子域包括:

按事務 / 兩階段提交(2pc)模式進行分解

你可以通過事務分解服務。然後,這樣一來系統裏將會存在多個事務。事務處理協調器是分佈式事務處理的重要參與者之一。分佈式事務包括兩個步驟:

2PC 的問題在於,和單個微服務的運行時間相比,它顯得相當慢。即便這些微服務跑在相同的網絡裏,它們之間的事務協調也確實會減慢系統速度,因此這種方法通常不適用於高負載情況。

絞殺者模式(Strangler Pattern)

上面三種,我們看到的這幾個設計模式都是用來分解綠場(Greenfield)的應用程序,但是往往我們所做的工作中有 80% 是針對灰場(brownfield)應用程序,它們是一些大型的單體應用程序(歷史遺留的代碼庫)。絞殺者模式可以解決這類問題。它會創建兩個單獨的應用程序,它們並排跑在同一個 URI 空間裏。隨着時間的流逝,直到最後,新重構的應用程序會 “幹掉” 或替換原有的應用程序,此時就可以關掉那個老的單體應用程序。絞殺應用程序的步驟分別是轉換,共存和消除:

隔艙模式(Bulkhead Pattern)

讓一個應用程序的元素和池子相對隔離,這樣一來,其他應用程序將可以繼續正常工作。這種模式被稱爲 “隔艙”,因爲它類似於船體的分段分區。根據使用者負載和可用性要求,將服務實例分成不同的組。這種設計有助於隔離故障,並允許用戶即使在故障期間仍可爲某些使用者維持服務。

邊車模式

該模式將一個應用程序的組件部署到一個單獨的處理器容器裏以提供隔離和封裝。它還允許應用程序由異構的組件和技術組成。這種模式被稱爲邊車模式(Sidecar),因爲它類似於連接到摩托車的側邊車。在該模式中,側邊車會附加到父應用程序,併爲該應用程序提供功能支持。Sidecar 還與父應用程序共享相同的生命週期,並與父應用程序一起創建和退出。Sidecar 模式有時也稱爲 sidekick 模式,這是我們在文章中列出的最後一個分解模式。

集成模式

API 網關模式

當一個應用程序被分解成多個較小的微服務時,這裏會出現一些需要解決的問題:

API 網關有助於解決微服務實現引發的諸多問題,而不僅限於上述提到的這些。

聚合器模式(Aggregator Pattern)

將業務功能分解成幾個較小的邏輯代碼段後就有必要考慮如何協同每個服務返回的數據。不能把這個職責留給消費者。

聚合器模式有助於解決這個問題。它討論瞭如何聚合來自不同服務的數據,然後將最終響應發送給消費者。這裏有兩種實現方式:

1、一個組合微服務將調用所有必需的微服務,合併數據,然後在發送回數據之前對其進行轉換合成

2、一個 API 網關還可以將請求劃分成多個微服務,然後在將數據發送給使用者之前彙總數據

如果要應用一些業務邏輯的話,建議選擇一個組合式的微服務。除此之外,API 網關作爲這個問題的解決方案已經是既定的事實標準。

代理模式

針對 API 網關,我們只是藉助它來對外公開我們的微服務。引入 API 網關後,我們得以獲得一些像安全性和對 API 進行分類這樣的 API 層面功能。在這個例子裏,API 網關有三個 API 模塊:

1、移動端 API,它實現了 FTGO 移動客戶端的 API 2、瀏覽器端 API,它實現了在瀏覽器裏運行的 JavaScript 應用程序的 API 3、公共 API,它實現了一些第三方開發人員需要的 API

網關路由模式

API 網關負責路由請求。一個 API 網關通過將請求路由到相應的服務來實現一些 API 操作。當 API 網關接收到請求時,它會查詢一個路由映射,該路由映射指定了將請求路由到哪個服務。一個路由映射可以將一個 HTTP 方法和路徑映射到服務的 HTTP URL。這種做法和像 NGINX 這樣的 Web 服務器提供的反向代理功能一樣。

鏈式微服務模式(Chained Microservice Pattern)

單個服務或者微服務將會有多級依賴,舉個例子:Sale 的微服務依賴 Product 微服務和 Order 微服務。鏈式微服務設計模式將幫助你提供合併後的請求結果。microservice-1 接收到請求後,該請求隨後與 microservice-2 進行通信,還有可能正在和 microservice-3 通信。所有這些服務都是同步調用。

分支模式

一個微服務可能需要從包括其他微服務在內的多個來源獲取數據。分支微服務模式是聚合器和鏈式設計模式的混合,並允許來自兩個或多個微服務的同時請求 / 響應處理。調用的微服務可以是一個微服務鏈。分支模式還可用於根據你的業務需求調用不同的微服務鏈或單個鏈。

客戶端 UI 組合模式

通過分解業務功能 / 子域來開發服務時,負責用戶體驗的服務必須從多個微服務中提取數據。在一個單體世界裏,過去只有一個從 UI 到後端服務的調用,它會檢索所有數據然後刷新 / 提交 UI 頁面。但是,現在不一樣了。對於微服務而言,我們必須把 UI 設計成一個具有屏幕 / 頁面的多個板塊 / 區域的框架。每個板塊都將調用一個單獨的後端微服務以提取數據。諸如 AngularJS 和 ReactJS 之類的框架可以幫助我們輕鬆地實現這一點。這些屏幕稱爲單頁應用程序(SPA)。每個團隊都開發一個客戶端 UI 組件,比如一個 AngularJS 指令,該組件實現其服務的頁面 / 屏幕區域。UI 團隊負責通過組合多個特定服務的 UI 組件來實現構建頁面 / 屏幕的頁面框架。

數據庫模式

給微服務定義數據庫架構時,我們需要考慮以下幾點:

1、服務必須是松耦合的。這樣它們可以獨立開發,部署和擴展

2、業務事務可能會強制跨越多個服務的不變量

3、一些業務事務需要查詢多個服務的數據

4、爲了可擴展性考慮,數據庫有時候必須是可複製和共享的

5、不同服務存在不同的數據存儲要求

每個服務一套數據庫

爲了解決上述問題,必須爲每個微服務設計一個數據庫。它必須僅專用於該服務。應當只能通過微服務的 API 訪問它。其他服務無法直接訪問它。比如,針對關係型數據庫,我們可以採用每個服務使用單獨的專用表(private-tables-per-service),每個服務單獨的數據庫模式(schema-per-service)或每個服務單獨的數據庫服務器(database-server-per-service)。

服務之間共享數據庫

我們已經說過,在微服務裏,爲每個服務分配一套單獨的數據庫是理想方案。採用共享數據庫在微服務裏屬於反模式。但是,如果應用程序是一個單體應用而且試圖拆分成微服務,那麼反正規化就不那麼容易了。在後面的階段裏,我們可以轉到每個服務一套數據庫的模式,直到我們完全做到了這一點。服務之間共享數據庫並不理想,但是對於上述情況,它是一個切實可行的解決方案。大多數人認爲這是微服務的反模式,但是對於灰場應用程序,這是將應用程序分解成更小邏輯部分的一個很好的開始。值得一提的是,這不應當應用於綠場應用程序。

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

一旦實現了每個服務分配單獨一套數據庫(database-per-service),自然就會產生查詢需求,這需要聯合來自多個服務的數據。然而這是不可能的。CQRS 建議將應用程序分成兩部分 —— 命令端和查詢端。

這通常會搭配事件驅動模式(event sourcing pattern)一起使用,一旦有任何數據更改便會創建對應的事件。通過訂閱事件流,我們便可以讓物化視圖保持更新。

事件驅動

絕大多數應用程序需要用到數據,典型的做法就是應用程序要維護當前狀態。例如,在傳統的創建,讀取,更新和刪除(CRUD)模型中,典型的數據流程是從存儲中讀取數據。它也包含了經常使用事務導致鎖定數據的限制。

事件驅動模式定義了一種方法,用於處理由一系列事件驅動的數據操作,每個事件都記錄在一個 append-only 的存儲中。應用程序代碼向事件存儲發送一系列事件,這些事件命令式的描述了對數據執行的每個操作,它們會被持久化到事件存儲。每個事件代表一組數據更改(例如,AddedItemToOrder)。

這些事件將保留在充當記錄系統的一個事件存儲裏。事件存儲發佈的事件的典型用途是在應用程序觸發的一些動作更改實體時維護這些實體的物化視圖,以及與外部系統集成。例如,一個系統可以維護一個用於填充 UI 部分所有客戶訂單的物化視圖。當應用程序添加新訂單,添加或刪除訂單中的項目以及添加運輸信息時,描述這些更改的事件將會得到處理並用於更新物化視圖。下圖展示了該模式的一個概覽。

Saga 模式

當每個服務都有它們自己的數據庫,並且一個業務事務跨越多個服務時,我們該如何確保各個服務之間的數據一致性呢?每個請求都有一個補償請求,它會在請求失敗時執行。這可以通過兩種方式實現:


可觀測性模式

日誌聚合

考慮一個應用程序包含多個服務的用例。請求通常跨越多個服務實例。每個服務實例均採用標準格式生成日誌文件。我們需要一個集中式的日誌記錄服務,該服務可以彙總每個服務實例的日誌。用戶可以搜索和分析日誌。他們可以配置在某些消息出現在日誌中時觸發告警。例如,PCF 就有日誌聚合器,它在應用側從 PCF 平臺的每個組件(router、controller、diego 等)收集日誌。AWS Cloud Watch 也是這樣做的。

性能指標

當服務組合由於引入了微服務架構而增加時,保持對事務的監控就變得尤爲關鍵了,如此一來就可以監控這些模式,而當有問題發生時便會發送告警。

此外,需要一個度量服務來收集有關單個操作的統計信息。它應當聚合一個應用服務的指標數據,它會用來報告和告警。這裏有兩種用於彙總指標的模型:

分佈式鏈路追蹤

在微服務架構裏,請求通常跨越多個服務。每個服務通過跨越多個服務執行一個或多個操作來處理請求。在排障時,有一個 Trace ID 是很有幫助的,我們可以端對端地跟蹤一個請求。

解決方案便是引入一個事務 ID。可以採用如下方式:

健康檢查

實施微服務架構後,服務可能會出現啓動了但是無法處理事務的情況。每個服務都需要有一個可用於檢查應用程序運行狀況的 API 端點,例如 /health。該 API 應該檢查主機的狀態,與其他服務 / 基礎設施的連接以及任何其他特定的邏輯。

橫切關注點模式(Cross-Cutting Concern Patterns)

外部配置

一個服務通常還會調用其他服務和數據庫。對於 dev,QA,UAT,Prod 等每個環境而言,API 端點的 URL 或某些配置屬性可能會有所不同。這些屬性中的任何一個更改都可能需要重新構建和重新部署服務。

爲避免代碼修改,可以使用配置。把所有配置放到外面,包括端點 URL 和證書。應用程序應該在啓動時或運行時加載它們。這些可以在啓動時由應用程序訪問,也可以在不重新啓動服務器的情況下進行刷新。

服務發現模式

在微服務出現時,我們需要在調用服務方面解決一些問題。

藉助容器技術,IP 地址可以動態地分配給服務實例。每次地址更改時,消費端服務都會中斷並且需要手動更改。

對於消費端服務來說,它們必須記住每個上游服務的 URL ,這就變成緊耦合了。

爲此,需要創建一個服務註冊中心,該註冊表將保留每個生產者服務的元數據和每個服務的配置。服務實例在啓動時應當註冊到註冊中心,而在關閉時應當註銷。服務發現有兩種類型:

熔斷器模式

一個服務通常會通過調用其他服務來檢索數據,而這時候下游服務可能已經掛了。這樣的話,有兩個問題:首先,請求將繼續抵達掛了的服務,耗盡網絡資源,並且降低性能。其次,用戶體驗將是糟糕且不可預測的。

消費端服務應通過代理來調用遠程服務,該代理的表現和一個電流斷路器類似。當連續的故障數超過閾值時,斷路器將跳閘,並且在超時期間內,所有調用遠程服務的嘗試都會立即失敗。超時到期後,斷路器將允許有限數量的測試請求通過。如果這些請求成功,斷路器則將恢復正常運行。否則,如果發生故障的話,超時時間則將再次重新開始計算。如果某些操作失敗概率很高的話,採取此模式有助於防止應用程序在故障發生後仍然不斷嘗試調用遠程服務或訪問共享資源。

藍綠部署模式

使用微服務架構時,一個應用可以被拆分成許多個微服務。如果我們採用停止所有服務然後再部署改進版本的方式的話,宕機時間將是非常可觀的,並且會影響業務。同樣,回滾也將是一場噩夢。藍綠部署模式可以避免這種情況。

實施藍綠部署策略可以用來減少或消除宕機。它通過運行兩個相同的生產環境,Blue 和 Green 來實現這一目標。假設 Green 是現有的活動實例,Blue 是該應用程序的新版本。在任何時候,只有一個環境處於活動狀態,該活動環境爲所有生產流量提供服務。所有云平臺均提供了用於實施藍綠部署的選項。

轉自:

colstuwjx.github.io/2020/01/%E7%BF%BB%E8%AF%91-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E5%8F%8A%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/cHW66TuCv1XSRqDMHaK3dQ