微服務能夠對企業產生積極影響。因此,了解如何處理微服務架構(MSA)以及一些微服務設計模式,一個微服務架構的一些通用目標或者設計原則是很有價值的。下面是在微服務架構方案中值得考慮的四個目標。
1、縮減成本:MSA將會降低設計、實現和維護IT服務的總體成本
2、加快發布速度:MSA將會加快服務從想法到部署的落地速度
3、增強彈性:MSA將會提升我們服務網絡的彈性
4、開啟可見性:MSA支持為服務和網絡提供更好的可見性
你需要了解建設微服務架構背后的幾個設計原則:
- 可擴展性
- 可用性
- 韌性
- 靈活性
- 獨立自主性,自治性
- 去中心化治理
- 故障隔離
- 自動裝配
- 通過 DevOps 持續交付
聽取上述原則,在你實施的解決方案或系統付諸實踐的同時,這也會帶來一些挑戰和問題。這些問題在許多解決方案中也很常見。使用正確及匹配的設計模式可以克服這些問題。微服務有一些設計模式,這可以大體分為五類。每類都包含許多具體的設計模式。下圖展示了這些設計模式。
分解模式
按業務功能進行分解
說白了,微服務就是要應用單一職責原則,把服務改造成松耦合式的。它可以按照業務功能進行分解。定義和業務功能相對應的服務。業務功能是一個來自業務架構建模的概念。它是一個企業為了創造價值而要去做的某些事情。一個業務功能往往對應于一個業務對象,比如:
- 訂單管理負責訂單
- 客戶管理則是負責客戶
按問題子域進行分解
按照業務功能來分解一個應用程序可能會是一個不錯的開始,但是你終將會遇到所謂的“神類”,它很難再被分解。這些類將在多個服務之間都是通用的??梢远x一些和領域驅動設計(DDD)里面的子域相對應的服務。DDD 把應用程序的問題空間 —— 也即是業務 —— 稱之為域。一個域由多個子域組成。每個子域對應業務的各個不同部分。
子域可以分為如下幾類:
-
核心 —— 業務的核心競爭力以及應用程序最有價值的部分
-
支撐 —— 和業務有關但并不是一個核心競爭力。這些可以在內部實現也可以外包
-
通用 —— 不特定于業務,而且在理想情況下可以使用現成的軟件實現
一個訂單管理的子域包括:
-
產品目錄服務
-
庫存管理服務
-
訂單管理服務
-
配送管理服務
按事務/兩階段提交(2pc)模式進行分解
你可以通過事務分解服務。然后,這樣一來系統里將會存在多個事務。事務處理協調器是分布式事務處理的重要參與者之一。分布式事務包括兩個步驟:
-
準備階段 —— 在這個階段,事務的所有參與者都準備提交并通知協調員他們已準備好完成事務
-
提交或回滾階段 —— 在這個階段,事務協調器向所有參與者發出提交或回滾命令
2PC 的問題在于,和單個微服務的運行時間相比,它顯得相當慢。即便這些微服務跑在相同的網絡里,它們之間的事務協調也確實會減慢系統速度,因此這種方法通常不適用于高負載情況。
絞殺者模式(Strangler Pattern)
上面三種,我們看到的這幾個設計模式都是用來分解綠場(Greenfield)的應用程序,但是往往我們所做的工作中有 80% 是針對灰場(brownfield)應用程序,它們是一些大型的單體應用程序(歷史遺留的代碼庫)。
絞殺者模式可以解決這類問題。它會創建兩個單獨的應用程序,它們并排跑在同一個 URI 空間里。隨著時間的流逝,直到最后,新重構的應用程序會“干掉”或替換原有的應用程序,此時就可以關掉那個老的單體應用程序。絞殺應用程序的步驟分別是轉換,共存和消除:
-
轉換(Transform) —— 使用現代方法創建一個并行的全新站點。
-
共存(Coexist) —— 讓現有站點保留一段時間。把針對現有站點的訪問重定向到新站點,以便逐步實現所需功能。
-
消除(Eliminate) —— 從現有站點中刪除舊功能。
隔艙模式(Bulkhead Pattern)
讓一個應用程序的元素和池子相對隔離,這樣一來,其他應用程序將可以繼續正常工作。這種模式被稱為“隔艙”,因為它類似于船體的分段分區。根據使用者負載和可用性要求,將服務實例分成不同的組。這種設計有助于隔離故障,并允許用戶即使在故障期間仍可為某些使用者維持服務。
邊車模式
該模式將一個應用程序的組件部署到一個單獨的處理器容器里以提供隔離和封裝。它還允許應用程序由異構的組件和技術組成。這種模式被稱為邊車模式(Sidecar),因為它類似于連接到摩托車的側邊車。在該模式中,側邊車會附加到父應用程序,并為該應用程序提供功能支持。Sidecar 還與父應用程序共享相同的生命周期,并與父應用程序一起創建和退出。Sidecar 模式有時也稱為 sidekick 模式,這是我們在文章中列出的最后一個分解模式。
集成模式
API 網關模式
當一個應用程序被分解成多個較小的微服務時,這里會出現一些需要解決的問題:
-
存在不同渠道對多個微服務的多次調用
-
需要處理不同類型的協議
-
不同的消費者可能需要不同的響應格式
API 網關有助于解決微服務實現引發的諸多問題,而不僅限于上述提到的這些。
-
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)模型中,典型的數據流程是從存儲中讀取數據。它也包含了經常使用事務導致鎖定數據的限制。
微信搜索公眾號:Java后端編程,回復:java 領取資料 。
事件驅動模式定義了一種方法,用于處理由一系列事件驅動的數據操作,每個事件都記錄在一個 Append-only 的存儲中。應用程序代碼向事件存儲發送一系列事件,這些事件命令式的描述了對數據執行的每個操作,它們會被持久化到事件存儲。每個事件代表一組數據更改(例如,AddedItemToOrder)。
這些事件將保留在充當記錄系統的一個事件存儲里。事件存儲發布的事件的典型用途是在應用程序觸發的一些動作更改實體時維護這些實體的物化視圖,以及與外部系統集成。例如,一個系統可以維護一個用于填充 UI 部分所有客戶訂單的物化視圖。當應用程序添加新訂單,添加或刪除訂單中的項目以及添加運輸信息時,描述這些更改的事件將會得到處理并用于更新物化視圖。下圖展示了該模式的一個概覽。
Saga模式
牛逼啊!接私活必備的 N 個開源項目!趕快收藏吧
當每個服務都有它們自己的數據庫,并且一個業務事務跨越多個服務時,我們該如何確保各個服務之間的數據一致性呢?每個請求都有一個補償請求,它會在請求失敗時執行。這可以通過兩種方式實現:
- 編舞(Choreography) —— 在沒有中央協調的情況下,每個服務都會生成并偵聽另一個服務的事件,并決定是否應該采取措施。編舞是一種指定兩個或多個參與方的方案。任何一方都無法控制對方的流程,或者對這些流程有任何可見性,無法協調他們的活動和流程以共享信息和值。當需要跨控制/可見性域進行協調時,請使用編舞的方式。參考一個簡單場景,你可以把編舞看作和網絡協議類似。它規定了各方之間可接受的請求和響應模式。sage pattern
- 編排(Orchestration) —— 一個編排器(對象)會負責 saga 的決策和業務邏輯排序。此時你可以控制流程中的所有參與者。當它們全部處于一個控制域時,你可以控制該活動的流程。當然,這通常是你被指派到一個擁有控制權的組織里制定業務流程。saga-pattern-orchestration
可觀測性模式
日志聚合
考慮一個應用程序包含多個服務的用例。請求通??缭蕉鄠€服務實例。每個服務實例均采用標準格式生成日志文件。我們需要一個集中式的日志記錄服務,該服務可以匯總每個服務實例的日志。
用戶可以搜索和分析日志。他們可以配置在某些消息出現在日志中時觸發告警。例如,PCF 就有日志聚合器,它在應用側從 PCF 平臺的每個組件(router、controller、diego等)收集日志。AWS Cloud Watch 也是這樣做的。
性能指標
當服務組合由于引入了微服務架構而增加時,保持對事務的監控就變得尤為關鍵了,如此一來就可以監控這些模式,而當有問題發生時便會發送告警。
此外,需要一個度量服務來收集有關單個操作的統計信息。它應當聚合一個應用服務的指標數據,它會用來報告和告警。這里有兩種用于匯總指標的模型:
- 推送 —— 服務將指標推送到指標服務,例如 NewRelic,AppDynamics
- 提取 —— 指標服務從服務中提取指標,例如 Prometheus
分布式鏈路追蹤
在微服務架構里,請求通常跨越多個服務。每個服務通過跨越多個服務執行一個或多個操作來處理請求。在排障時,有一個 Trace ID 是很有幫助的,我們可以端對端地跟蹤一個請求。
解決方案便是引入一個事務ID。可以采用如下方式:
- 為每個外部請求分配一個唯一的外部請求ID
- 將外部請求ID傳遞給處理該請求鏈路的所有服務
- 在所有日志消息中加入該外部請求ID
健康檢查
實施微服務架構后,服務可能會出現啟動了但是無法處理事務的情況。每個服務都需要有一個可用于檢查應用程序運行狀況的 API 端點,例如 /health。該 API 應該檢查主機的狀態,與其他服務/基礎設施的連接以及任何其他特定的邏輯。
橫切關注點模式(Cross-Cutting Concern Patterns)
外部配置
一個服務通常還會調用其他服務和數據庫。對于dev,QA,UAT,Prod等每個環境而言,API 端點的 URL 或某些配置屬性可能會有所不同。這些屬性中的任何一個更改都可能需要重新構建和重新部署服務。
為避免代碼修改,可以使用配置。把所有配置放到外面,包括端點 URL 和證書。應用程序應該在啟動時或運行時加載它們。這些可以在啟動時由應用程序訪問,也可以在不重新啟動服務器的情況下進行刷新。
服務發現模式
在微服務出現時,我們需要在調用服務方面解決一些問題。
借助容器技術,IP地址可以動態地分配給服務實例。每次地址更改時,消費端服務都會中斷并且需要手動更改。
對于消費端服務來說,它們必須記住每個上游服務的 URL ,這就變成緊耦合了。
為此,需要創建一個服務注冊中心,該注冊表將保留每個生產者服務的元數據和每個服務的配置。服務實例在啟動時應當注冊到注冊中心,而在關閉時應當注銷。服務發現有兩種類型:
- 客戶端:例如?.NETflix Eureka
- 服務端:例如:AWS ALB
熔斷器模式
一個服務通常會通過調用其他服務來檢索數據,而這時候下游服務可能已經掛了。這樣的話,有兩個問題:首先,請求將繼續抵達掛了的服務,耗盡網絡資源,并且降低性能。其次,用戶體驗將是糟糕且不可預測的。
消費端服務應通過代理來調用遠程服務,該代理的表現和一個電流斷路器類似。當連續的故障數超過閾值時,斷路器將跳閘,并且在超時期間內,所有調用遠程服務的嘗試都會立即失敗。超時到期后,斷路器將允許有限數量的測試請求通過。
如果這些請求成功,斷路器則將恢復正常運行。否則,如果發生故障的話,超時時間則將再次重新開始計算。如果某些操作失敗概率很高的話,采取此模式有助于防止應用程序在故障發生后仍然不斷嘗試調用遠程服務或訪問共享資源。
藍綠部署模式
使用微服務架構時,一個應用可以被拆分成許多個微服務。如果我們采用停止所有服務然后再部署改進版本的方式的話,宕機時間將是非??捎^的,并且會影響業務。同樣,回滾也將是一場噩夢。藍綠部署模式可以避免這種情況。
實施藍綠部署策略可以用來減少或消除宕機。它通過運行兩個相同的生產環境,Blue 和Green 來實現這一目標。假設 Green 是現有的活動實例,Blue 是該應用程序的新版本。在任何時候,只有一個環境處于活動狀態,該活動環境為所有生產流量提供服務。所有云平臺均提供了用于實施藍綠部署的選項。