(一)概述
微服務能在企業中發揮積極作用。因此了解微服務架構(MSA)設計的一般目標或原則,以及一些微服務的設計模式,都是是很有意義的
- 降低成本:MSA 降低了 IT 服務的設計、實現和管理的總體成本
- 提高交付速度:MSA 能夠提高服務的實現速度
- 增強健壯性:MSA 能夠增強我們服務網絡的健壯性
- 提供可視化支持:MSA 能夠為服務和網絡提供更好的可視化支持
(二)微服務架構的構建原則
- 伸縮能力
- 可用性
- 健壯性
- 彈性
- 獨立的匿名服務
- 去中心化的治理
- 故障隔離
- 自動供給
- 通過 DevOps 實現持續交付
在系統建設中,堅持上述原則會遭遇很多挑戰和問題。這些問題在很多解決方案中都會出現。如果能夠正確的使用合適的設計模式,就能夠克服這些問題。微服務的設計模式可以分為五大類,每個大類中都包含一些設計模式
(三)拆分模式
1、根據業務拆分
根據業務能力進行分解的方式,能降低服務耦合度,實現單一職責的服務目標。這里說的業務能力是來自業務架構模型的一個概念,是企業用來創造價值的行為。業務能力通常對應到業務對象上,例如:
- 訂單管理負責訂單
- 客戶管理負責客戶
2、利用子域拆分
使用業務能力對應用進行拆分是個好的開端,但是往往會遇到不易分解的超級類。這種超級類在很多服務中都很普遍。用 DDD 子域來進行服務的定義。DDD 把應用的問題空間(業務)當作領域。一個領域由多個子域構成。每個子域負責業務的不同部分。子域可以分為幾類:
- 核心: 業務中的關鍵差異因素,也是應用程序中的價值核心
- 支撐: 和業務有關,但並非關鍵差異;可以自建,也可以外包
- 通用: 並不針對業務,理想情況下,可以使用現成的軟件實現
訂單管理的子域包括:
- 產品類目服務
- 庫存管理服務
- 訂單管理服務
- 配送管理服務
3、根據事務拆分
這種模式可以分解事務上的服務,這樣系統中就會有會有多個事務。分布式事務中的一個重要概念就是事務協調者。分布式事務 (兩階段提交) 由兩個步驟組成:
- 准備階段: 這個階段中,事務的所有參與者都做好准備,並通知事務協調者,它們已經准備好完成事務
- 提交或歸滾階段: 這個階段里,事務協調者會向所有參與方發出提交或回滾命令
注意: 相對於單一微服務來說,兩段提交的問題就是慢。在微服務之間進行事務協調,就算是在同一網絡中,也會拖慢系統;所以這種方式在高負載場景中並不常見
3、扼殺者模式
前面三個設計模式都是對 綠地 (Greenfiled) 應用進行拆分,但是還有 80% 的 棕地 (Brownfiled) 需要對付 —— 它們是傳統、龐大的單體應用。扼殺者模式為此而生。這種模式會創建兩個獨立的應用,一同運行在同樣的 URI 空間中。隨着時間點的推移,新的重構了的應用會扼殺或者替換掉原有應用,最后就可以關掉單體應用了。這種模式分為 轉換、共存 和 終結 三個步驟
4、艙壁模式
這個模式把應用的元素隔離開來,這樣一個失敗之后,其它的還能繼續工作。這個模式可以類比船體結構,因此被稱為艙壁。根據消費者的負載以及可用性要求,把服務分割為不同的群。這種設計能夠對故障進行隔離,即使遇到故障,也能為部分消費者提供服務
注: 艙壁模式(Bulkhead)隔離了每個工作負載或服務的關鍵資源,如連接池、內存和 CPU,使用艙壁避免了單個工作負載(或服務)消耗掉所有資源,從而導致其他服務出現故障的場景,這種模式主要是通過防止由一個服務引起的級聯故障來增加系統的彈性(艙壁模式降低依賴服務對整個系統的影響,保護有限的資源不被耗盡,增加了系統得到彈性)
5、Sidecar 模式
這種模式把應用的組件部署到一個不同的容器中,從而更好地完成隔離和封裝。這種模式讓應用能夠把多種組件和技術整合在一起。這種模式的情況很像摩托車的挎斗,因此被稱為 Sidecar,Sidecar 附着在主應用上,並且為主應用提供支持能力。Sidecar 還和主應用共享同樣的生命周期,它的創建和銷毀都是和主應用同步進行的。Sidecar 模式有時也被稱為 Sidekick 模式
(四)集成模式
1、API 網關模式
應用被分解成更小的微服務之后,就會出現一些待解決的問題
- 如何處理來自不同渠道的不同微服務的調用
- 如何處理不同的協議
- 不同消費者可能需要不同格式的響應
API 網關就是用來處理這類問題的
- API 網關是所有微服務調用的單一入口
- 可以作為代理服務器,將特定請求路由到特定微服務
- 可以把調用結果進行聚合,發回給消費者
- 可以為每種類型的客戶端創建細粒度的 API
- 還能轉化請求和響應的協議
- 可以代微服務進行認證、鑒權的工作
2、聚合模式
業務功能被分拆為多個更小的代碼段之后,如何把各個微服務返回的數據進行整合就是個問題了。這種責任不應該拋給消費者自行解決。聚合模式可以解決這種問題,這種模式的關鍵是如何把多個不同服務的響應數據進行聚合,然后將最終響應發回給消費者。可以用兩種方式來完成任務:
- 用一個復合微服務調用所有必須的微服務,把數據拼裝成合適的結果發回給客戶端
- 用 API 網關把請求拆分為對多個微服務的調用,然后聚合返回結果發回給客戶端
如果這一過程中有業務邏輯,推薦使用復合微服務的方式。其它情況下,API 網關是個好方法
3、代理模式
這種 API 網關只會使用 API 網關開放微服務。例如一個 API 網關有三個 API 模塊:
- 移動 API: 為手機客戶端提供 API
- 瀏覽器 API: 為瀏覽器中運行的 JavaScript 應用提供 API
- 公共 API: 為第三方開發者提供的 API
4、路由網關模式
這種 API 網關負責對請求進行路由。它通過將請求路由給特定服務的方式來完成 API 調用。當它接到請求的時候,會根據請求在路由表中查找合適的服務。舉個例子來說,路由表可能會將一個 HTTP 方法和路徑映射為服務的 HTTP URL。這種能力和 NGINX 等服務器的反向代理功能一致
5、鏈式微服務模式
有的微服務會有多種依賴,例如銷售服務依賴於產品和訂單服務。鏈式微服務模式能夠為請求提供合並的結果,微服務 1 收到的請求會向后傳遞給微服務 2 和微服務 3。所有這些服務都是同步調用
6、分支模式
微服務可能需要從多個數據源(或者微服務)獲取數據。分支模式是聚合模式和鏈式模式的混合體,用來並行的處理兩個或更多個微服務進行交互。被調用的微服務可以是一個微服務組成的鏈條。分支模式還可以根據業務需要,調用多個或者一個微服務鏈條
7、客戶端分解模式
根據業務功能或者子域進行解耦,完成服務開發之后,負責用戶體驗的服務必須從多個微服務拉取數據。在單體服務的世界中,UI 接收到請求之后,只需要一次后端調用就能夠獲取所有數據,從而完成刷新或提交動作。然而現在不同了。在微服務的環境下,UI 要把頁面 / 屏幕分割為多個區域。每個區域會調用獨立的微服務來獲取數據。AngularJS 或者 ReactJS 這樣的框架能夠簡化這些工作。在單頁面應用(SPA)中,每個微服務都有自己對應的頁面組件。UI 團隊要負責把多個特定服務的 UI 組件組裝起來,形成頁面骨架,最終完成整體頁面 / 屏幕的輸出
(五)數據庫模式
在微服務中定義數據庫架構,需要考慮幾個要點:
- 服務必須松耦合。可以獨立的被開發、部署以及擴縮容
- 業務事務可能需跨越多個服務
- 有的業務事務需要查詢隸屬於多個服務的多種數據
- 數據庫必須能夠被復制或者共享從而滿足規模要求
- 不同服務有不同的數據存儲需求
1、服務獨占數據庫
為了滿足上述要素,每個服務必須擁有各自的數據庫;數據庫必須被特定服務所獨占。對這些獨占數據是不能直接訪問的,只能通過微服務 API 進行數據訪問。例如關系型數據庫來說,可以用服務專屬的數據表、專屬結構或者專屬數據庫
2、服務共享數據庫
微服務領域的理想情況就是每個服務都獨占數據庫。那么共享數據庫就是反模式的。但是在單體應用拆分為微服務的過程中可就沒那么容易了。后面的階段中,可以轉向每個服務獨占數據庫的模式。共享數據庫並不理想,但是在遷移過程中是有用的。多數人會認為這不符合微服務需求,但是對於既有應用,這是一個好的拆分起點。綠地應用就不該這樣了
3、命令查詢隔離
命令和查詢的隔離 (CQRS),一旦實現了服務獨占數據的模式,就有了拼接多個服務的數據的需要。CQRS 把應用分成兩部分 —— 命令和查詢
- 命令端用來處理創建、更新和刪除
- 查詢端用物化視圖來處理查詢
事件源模式會為任何數據變更創建事件。物化視圖訂閱事件流,以此來保持更新。事件源模式的典型用法就是根據數據來管理應用程序的當前狀態。例如傳統的增刪改查模型是從存儲讀取數據的。這其中存在鎖定數據的需要,通常要用事務來解決
4、事件源模式
事件源模式定義了處理數據操作的方法,以事件序列進行驅動,每個事件都記錄在只支持追加寫入的存儲之中。應用程序會發送一系列事件,這些事件把每個數據操作強制寫入到存儲之中進行持久化。每個事件代表對數據的一些修改(例如 AddedItemToOrder)。這些事件保存在事件庫中。事件庫中發布的事件,其典型用途就是在應用修改實體時,維持物化視圖的狀態,可以用於外部系統的集成。例如一個系統可以維護一個所有客戶訂單的物化視圖,這個視圖用於在 UI 中展示。在應用加入新訂單、或者在訂單的項目中進行增刪以及修改送貨信息時,這些變更產生的事件就可以用來更新物化視圖。下圖描述了這個模式的概況
5、Saga 模式
在每個服務都有了自己的數據庫之后,如果出現了跨服務的事務的時候,如何確認服務的數據一致性呢?在請求失敗時,每個請求都要執行一個補償請求。可以用兩種方式來實現
- 沒有中央協調機制,每個服務都會生成事件,也監聽別的服務的事件,從而對是否采取動作進行決策。這是一種兩方或多方的協作方式,任何一方都沒有控制其它成員的能力,甚至可能對其它成員都是不可見的。這種做法能夠對活動進行協調,並且能分享信息和價值。在跨越域或者可見區域進行協調時就可以用這種方法。在簡單場景中,可以和網絡協議類比,它定義了各參與方之間的請求和響應模式
- 使用編排器負責決策,對業務邏輯進行排序。如果能夠對過程中所有參與者都有控制權,並且他們都存在於同一個控制域,就可以控制活動的流程了。這種情況多見於組織內部的業務流程
(六)觀察模型
1、日志聚合
日志聚合針對的是包含多個服務的應用。請求經常會跨越多個服務實例。每個服務實例都生成標准格式的日志文件。我們需要一個中央日志服務,把各個服務實例的日志聚合起來。用戶可以對日志進行搜索和分析。可以對日志系統進行配置,如果出現了特定信息,就觸發告警。例如 PCF 的日志聚合器會從 PCF 的每個組件(router、controller、diego 等)和應用中搜集日志。AWS 的 Cloud Watch 也做了同樣的事情
2、性能指標
微服務架構下服務數量會急劇增加,就需要提高監控的重視程度,在問題發生時,才能及時的發送警報。需要有一個度量服務來收集各種統計信息。應用提供的報告和告警都應該發送給這個服務。聚合指標有兩種模型:
- 推: 服務把指標推送給監控服務,例如 NewRelic、AppDynamics
- 拉: 監控服務自行拉取指標數據,例如 Prometheus
3、分布式追蹤
微服務架構下,請求經常會跨越多個服務。每個服務又要用一個或多個操作,調用多個服務來處理請求。要對請求進行端到端的跟蹤,有個跟蹤 ID 會非常有幫助。可以用下列方法來引入事務 ID 從而解決這一問題:
- 為每個外部請求分配一個唯一的外部請求 ID
- 把外部請求的 ID 傳遞到所有服務
- 在所有日志信息中輸出這一外部的請求 ID
4、健康檢查
實現了微服務架構之后,微服務自身可能出現無法處理業務的情況。每個服務都需要有一個端點,用來檢查應用的健康情況。這個 API 可以檢查主機的狀態、到其它服務、基礎設施的連接情況,以及一些別的邏輯
(七)跨領域模式
1、外部化配置
服務通常會調用其它服務以及數據庫。多個環境中,例如開發、測試、生產等,端點地址或者一些配置屬性可能不同。這些屬性中的任何變動都可能需要服務的重新構建和部署。為了這種情況,建議使用外部配置,例如 URL 和登錄憑據。應用應該在啟動時或者隨時載入配置
2、服務發現模式
實現微服務時,我們需要解決一些調用服務的問題。在容器環境中,IP 地址是動態分配給服務實例的。每一次地址變更,消費者服務都會受到影響,需要隨之變更。消費者服務需要記住每個服務的地址,這樣就形成了一種緊耦合。可以創建服務注冊表,用於保存每個生產者服務的元數據以及規范信息。服務實例在啟動時應該進行注冊,並在關閉時解除注冊。服務發現有兩種方式:
- 客戶端: 例如 Netflix Eureka
- 服務端: 例如 AWS ALB
3、熔斷模式
服務通常需要調用其它服務來獲取數據,有時候下游服務會出現故障無法提供服務。這種情況下有兩個問題:
- 首先,請求會持續發送給宕機的服務,耗盡網絡資源,降低性能
- 其次,用戶體驗會變差,結果也無法預測
消費者應該通過代理服務器調用遠程服務,這個代理可以扮演電路中的熔斷器的角色。當錯誤持續出現到一個閾值時,熔斷行為被觸發,在一定時間內,所有調用該服務的請求都會立刻失敗。時間窗口過后,熔斷器允許一定數量的訪問嘗試。如果這些嘗試成功了,熔斷器恢復為正常的放行狀態;如果再次出現故障,就再次進入開路狀態。要調用一個容易故障的服務或共享資源,這種模式非常有用
4、藍綠部署模式
在微服務架構中,一個應用會由多個服務構成,如果停掉所有服務,部署一個增強版本,停機時間會對業務造成很大影響。同樣回滾過程也會是一個噩夢。藍綠部署模式避免了這種問題。藍綠部署的策略能夠降低或免除服務的停機時間。這種策略同時運行兩個一致的生產環境,用這種方式來解決問題。假設綠色是現存的服務實例,而藍色是新版本。任何時間里,只有一個環境是在線的,這個在線環境會處理所有生產通信。所有的雲平台都提供了藍綠部署的支持
轉自:有夢想的咸魚