基本上在産品的最開始階段,為了快速建構産品,都是單體架構,盡快我們也會按照業務劃分子產品,但是這個樣子始終最終部署的時候還是單體式應用。
如我們早期可以使用Python 的Django快速疊代一個web應用,我們會在Django中劃分不同的子產品,也就是Django中的app。
而随着業務的疊代發展,項目越來越複雜,可能就會導緻應用的擴充,可靠性越來越低,最終導緻靈活開發和自動化部署變得無法完成。
微服務定義
關于SOA
!! 面向服務的架構(SOA)是一個元件模型,它将應用程式的不同功能單元(稱為服務)進行拆分,并通過這些服務之間定義良好的接口和協定聯系起來。接口是采用中立的方式進行定義的,它應該獨立于實作服務的硬體平台、作業系統和程式設計語言。這使得建構在各種各樣的系統中的服務可以以一種統一和通用的方式進行互動。
是以我們可以把微服務看做是SOA的一種實踐:
- 小即是美:小的服務代碼少,bug也少,易于測試,易于維護,也更容易不斷疊代完善。
- 單一職責:一個服務隻需要幹好一件事情,專注才能做好。
什麼是微服務?
圍繞業務功能建構的,服務關注單一業務,服務間采用輕量級的通信機制,可以全自動獨立部署,可以使用不同的程式設計語言和資料存儲技術。微服務架構通過業務拆分實作服務元件化,通過元件組合快速開發系統,業務單一的服務元件又可以獨立部署,使整個系統變得清晰靈活。
- 原子服務
- 獨立程序
- 隔離部署
- 去中心化服務治理
!! 注意:基礎設施的建設,複雜度高。
自己的了解:
- 簡單說就是微小的服務或應用,比如linux上的各種工具:ls,cat,awk等
- 微服務就是讓每個小的服務專注的做好一件事
- 每個服務單獨開發和部署,服務之間是完全隔離的
微服務的優缺點
微服務也不是萬金油,并不是所有的情況都需要做成微服務,同時微服務也有自己的缺點或者說微服務也會帶來一些問題:
- 微服務應用是分布式系統,是以系統必然會比單體應用的時候複雜:開發者不得不使用RPC或者消息傳遞來實作程序間通信;必須要寫代碼來處理消息傳遞中速度過慢或者服務不可用等局部失效問題。
- 分區的資料庫架構,同時更新多個業務主體的事務很普遍。這種事務對單體式應用來說很容易,因為隻有一個資料庫。在微服務架構中,需要更新不同服務使用的不同的資料庫,進而對開發者提供了更高的要求和挑戰。
- 測試一個基于微服務的應用也變的很複雜。
- 服務子產品的依賴,應用的更新可能會涉及多個服務子產品的修改。
優點:
- 疊代周期短,極大的提升開發效率
- 獨立部署,獨立開發
- 可伸縮性好,能夠針對指定的服務進行伸縮
- 故障隔離,不會互相影響
缺點:
- 複雜度增加,一個請求往往要經過多個服務,請求鍊路比較長
- 監控和定位問題困難
- 服務管理比較複雜
元件化服務
微服務的核心是元件化服務,通過将之前複雜的巨石機構,拆分成不同的服務,來實作元件化。即将應用拆散為一系列的服務運作在不同的程序中。單一的服務變化隻需要重新部署對應的服務程序。
去中心化
- 資料去中心化
- 治理去中心化
- 技術去中心化
!! 注:治理區中心化,可以了解為消除架構中的熱點,例如,我們通常在架構中使用的Nginx,所有的流量都會先經過Nginx,雖然也可以擴容,但是相對來說收益就比較低。
每個服務獨享自身的資料存儲設施(緩存,資料庫等),而不是像傳統應用共享一個緩存和資料庫,這樣有利于服務的獨立性,隔離相關幹擾。
基礎設施自動化
無自動化不微服務。自動化包括測試和部署。
單一程序的傳統應用被拆分為一系列的多程序服務後,意味着開發,調試,測試,監控和部署的複雜度會增加,必須要有合适的自動化基礎設施來支援微服務架構,否則開發和運維的成本會大大增加。
- CICD
- Testing
- K8s
落地微服務的關鍵因素
配套設施:
- 微服務架構研發和維護
- 打包,版本管理,上線平台支援
- 硬體層支援,比如容易和容器排程
- 服務治理平台支援,比如分布式鍊路追蹤和監控
- 測試自動化支援,比如上線前自動化case
組織架構:
- 微服務架構開發團隊
- 私有雲研發團隊
- 測試平台研發團隊
硬體層架構:

可用性 & 相容性設計: 微服務架構采用粗力度的程序間通信。關于可用性和相容性主要包含以下方面:
- 隔離
- 逾時控制
- 負載保護
- 限流
- 降級
- 重試
- 負載均衡
!! 注意:服務的提供者的變更可能引發服務消費者的相容性破壞,時刻謹記服務契約的相容性。總結一句話:發送時要保守,接收時要開放。
微服務設計
API Gateway
常見的開源網關:Kong, APSix,
面向使用者場景的 API,而不是面向資源的API
BFF(Backend for Frontend) 可以認為是一種适配服務,将後端的微服務進行适配(主要包括聚合裁剪和适配邏輯),向無線端裝置暴露友好和統一的API,友善無線裝置介入通路後端服務。
BFF 可以了解為主要進行資料的組裝,業務場景的聚合API
網關在微服務架構中承擔着非常重要的角色,它是解偶拆分和後續更新的利器。在網關的配合下,單塊BFF 實作解偶拆分,各業務團隊可以獨立開發和傳遞各自的微服務。
把跨橫切面邏輯從BFF 剝離到網關上,BFF的開發可以更加專注于業務邏輯傳遞。實作架構上的關注分離。
Mircoservice劃分
相對來說有兩種不同不同的劃分服務邊界:通過業務職能(Business Capability)劃分和DDD的限界上下文(Bounded Context)
Business Capability: 由公司内部不同部門提供的職能 Bounded Context:這裡的業務邊界的含義是“解決不同業務問題”的問題域和對應的解決方案域,為了解決某種類型的業務問題,貼近領域知識,也就是業務。
DDD 通過領域對象之間的互動實作業務邏輯與流程,并通過分層的方式将業務邏輯剝離出來,單獨進行維護,進而控制業務本身的複雜度。
!! 注意:微服務與微服務之間不是通過資料耦合的,是以微服與微服務之間都是通過接口調用,一定不是通過資料,服務與服務之間資料是隔離的。
什麼是CQRS
CQRS — Command Query Responsibility Segregation,顧名思義是将 command 與 query 分離的一種模式。
CQRS 将系統中的操作分為兩類,即「指令」(Command) 與「查詢」(Query)。指令則是對會引起資料發生變化操作的總稱,即我們常說的新增,更新,删除這些操作,都是指令。而查詢則和字面意思一樣,即不會對資料産生變化的操作,隻是按照某些條件查找資料。
CQRS 的核心思想是将這兩類不同的操作進行分離,然後在兩個獨立的「服務」中實作。這裡的「服務」一般是指兩個獨立部署的應用。在某些特殊情況下,也可以部署在同一個應用内的不同接口上。
Command 與 Query 對應的資料源也應該是互相獨立的,即更新操作在一個資料源,而查詢操作在另一個資料源上。
Mircoservice安全
關于外網的請求,通常在API Gateway進行統一的認證攔截,認證成功後,使用JWT方式通過RPC中繼資料傳遞的方式帶到BFF層,BFF校驗Token完整性後把身份資訊注入到應用的Context中,BFF到其他下層的微服務,建議是直接在RPC Request中帶入使用者身份資訊(UserID)請求服務
對于服務内部,一般要區分身份認證和授權
對于身份認證 :如果是gRPC,可以很容易進行身份認證,如:證書…
對于授權 :通過配置中心做一個RBAC的服務,下發到服務,服務加載的時候就可以很容易建構一個RBAC的認證,進而判斷這個請求是否有權限。
gRPC && 服務發現
- 多語言:語言中立,支援多種語言
- 輕量級,高性能:序列化支援PB(Protocol Buffer) 和JSON, PB是一種語言無關的高性能序列化架構
- 可插拔
- IDL:基于檔案定義服務,通過proto3工具生成指定語言的資料結構/服務端接口以及用戶端Stub
- 設計理念:如中繼資料的傳遞
- 移動端:基于标準的HTTP2設計,支援雙向流,消息頭壓縮,單TCP的多路複用/服務端推送等特性。
- 服務而非對象,消息而非引用:促進微服務的系統間粗粒度消息互動設計理念
- 負載無關的:不同的服務需要使用不同的消息類型和編碼
- 流:streaming API
- 阻塞式和非阻塞式:支援異步和同步處理在用戶端和服務端互動的消息序列
- 中繼資料交換:常見的橫切關注點,如認證或追蹤,依賴資料交換。
- 标準化狀态碼:用戶端通常以有限的方式響應API調用傳回的錯誤
Health Check
gRPC 有一個标準的健康監測協定,在gRPC的所有語言實作中基本都提供了生成代碼和用于設定運作狀态的功能。
主動健康檢查可以在服務提供者服務不穩定時,被消費者所感覺,臨時從負載均衡中摘除,減少錯誤請求。當服務提供這重新穩定後,health check 成功,重新加入到消費者的負載均衡中,回複請求,health check 同樣也被用于外挂方式的容器健康檢測,或者流量檢測
healthCheck 可以做什麼呢?
- 在我們的服務注冊與發現中,假如服務的提供者Provider到Discoery 之間通信是正常的,但是我們的服務調用者Consumer到服務提供者Provider之間出現網絡問題,這個時候如果沒有健康檢查,我們的服務調用這就會繼續調用,但是這個時候其實是會調用失敗的,而healthCheck 就可以避免這種情況的發生。它會對從Discoery中擷取到的Provider進行健康檢查,雖然Discoery中有這個Provider,但是如果健康檢查有問題,那麼就會把這個provider進行剔除。避免調用失敗的問題。
- 平滑釋出
服務發現
CAP原理
- C: consistency, 一緻性,每次總是能夠讀到最近寫入的資料或者失敗
- A: available, 每次請求都能讀到資料
- P: partition tolerance 分區容忍,不管任意個消息由于網絡原因失敗,系統都能能夠繼續工作
CAP原理中,P是必須滿足的,C 和A 可以根據業務需要選擇,要麼是CP系統,要麼是AP系統。
用戶端發現
一個服務執行個體啟動時,它的網絡位址會被注冊到注冊中心,當服務執行個體終止時,再從注冊中心删除。這個服務執行個體的系統資料庫通過心跳機制動态重新整理;用戶端使用一個負載均衡算法,去選擇一個可用的服務執行個體,來響應這個請求。
服務端發現
用戶端通過負載均衡器向一個服務發送請求,這個負載均衡器會查詢服務系統資料庫,并将請求路由到可用的服務執行個體上。服務執行個體在服務系統資料庫上被注冊和登出
對比兩種服務發現:
- 用戶端發現:直連,比服務端服務發現少一次網絡跳轉,Consumer需要内置特定的服務發現用戶端和發現邏輯。
- 服務端發現:Consumer無需關注服務發現具體細節,隻需要知道服務的DNS域名即可,支援異構語言開發,需要基礎設施支撐,多了一次網絡跳轉,可能有性能損失。
推薦的服務發現, 學習代碼參考:
!! https://nacos.io/zh-cn/docs/what-is-nacos.html https://github.com/bilibili/discovery
服務發現中的保護機制:
- 如果發現短時間内大量服務提供這下線,會開啟自我保護模式。這個時候不會剔除服務。
- 如果服務消費者和服務注冊中心通信故障,這個時候本身服務消費者會緩存配置,即使短時間内通信故障也不會有太大影響。
多叢集 & 多租戶
對于特别重要的服務通常是要考慮多級群。
- 從單一叢集考慮,多個節點保證可用性,我們通常使用N+2的方式來備援節點。
- 從單一叢集故障帶來的影響面角度考慮備援多套叢集。
- 單個機房内的機房故障導緻的問題。
多套備援的叢集對應多套獨占的緩存,帶來更好的性能和備援能力, 盡量避免業務隔離使用或者 sharding 帶來的 cache hit 影響(按照業務劃分叢集資源)
但是這裡會有一個問題需要考慮:
根據不同的業務劃分叢集後,如果其中一個業務的進群挂了之後,将流量切到正常叢集的時候,這個時候因為獨占緩存,是以就會導緻産生到兩的cache miss 透傳到DB,這個時候DB的壓力會瞬間變大。
解決辦法:可以和所有叢集建立連接配接,通過負載均衡的方式,這樣請求就會均攤的打到不同的叢集中 上,進而防止緩存擊穿的情況。
注意這裡還有一個問題:
對于服務中的個别服務可能會存在有大量的其他服務都會依賴這個服務的情況,如帳号服務,那麼這個時候health check 的檢查可能會占用一定的資源,并且随着規模的增加,光health check 就會占用非常高的資源,如何解決這個問題呢?
是否可以從全叢集中選取一批節點(子集),利于劃分子集限制連接配接池大小?
通常20-100個後端,部分場景需要大子集,比如批量讀寫操作。後端平均分給用戶端。用戶端重新開機,保持重新均衡,同時對後端重新開機保持透明,同時連接配接的變動最小。需要思考這個算法的實作。
多租戶
!! 在一個微服務架構中允許系統共存是利用微服務穩定性及子產品化最有效的方式之一。這種方式一般被稱為多租戶。租戶卡一是測試,金絲雀釋出,影子系統,甚至服務層或産品線,使用租戶能夠保證代碼的隔離性并且能夠基于流量租戶做路由決策。
多租戶就是解決RPC的路由或者叫做RPC染色
并行測試需要一個和生産環境一樣的過渡(staging)環境,并且隻是用來處理測試流量。在并行測試中,工程師團隊首先完成生産服務的一次變動,然後将變動的代碼部署到測試棧,這種方法可以在不影響生産環境的情況下讓開發者穩定的測試服務,同時能夠在釋出前更容易的識别和控制bug,盡管并行測試是一種非常有效的內建測試方法,但是它也帶來了一些可能影響服務架構成功的挑戰:
- 混用環境導緻的不可靠測試
- 多套環境帶來的硬體成本
- 難以做負載測試,仿真線上真實流量情況
使用這種方法(内部叫染色釋出),我們可以把待測試的服務 B 在一個隔離的沙盒環境中啟動,并且在沙盒環境下可以通路內建環境(UAT) C 和D。我們把測試流量路由到服務 B,同時保持生産流量正常流入到內建服務。服務 B 僅僅處理測試流量而不處理生産流量。另外要確定內建流量不要被測試流量影響。生産中的測試提出了兩個基本要求,它們也構成了多租戶體系結構的基礎:
- 流量路由:能夠基于流入棧中的流量類型做路由。
- 隔離性:能夠可靠的隔離測試和生産中的資源,這樣可以保證對于關鍵業務微服務沒有副作用。
這裡可以了解為,對于不同的流量差別對待,對于測試的流量,也會在請求的時候帶上對應的染色标記,這樣到達系統的時候就會根據不同的染色标記走不同的路由,路由到具有相同染色的服務上。
小結
對于微服整體有一認識對于公司現有系統架構的一些思考,慢慢對公司現有架構整理出自己的意見和一些可行性的方案
如果覺得本文對你有幫助,可以點贊關注支援一下,也可以點進我首頁關注我公衆号,上面有更多技術幹貨文章以及相關資料共享,大家一起學習進步!