微服務實踐系列一之微服務架構

單體架構

在引入微服務架構之前,由於業務需求簡單,我做的應用基本都是如下的單體架構。

使用 Golang 編寫 API 模塊主要劃分爲三層設計。

  1. Controller,服務入口,負責處理路由,參數校驗,請求轉發。

  2. Service,邏輯(服務)層,業務邏輯的入口,默認這裏所有的請求參數一定是合法的了。業務邏輯和業務流程也都在這一層中。

  3. DAO,這一層主要負責和數據、存儲打交道。將下層存儲以更簡單的函數、接口形式暴露給 Service 層來使用。負責數據的持久化工作。

單體架構的特點就是將所有的功能集成在一個項目工程裏了,部署時,得益於 golang 的強大😁,只要使用 go build 工具打包出二進制文件後放到服務器上就可以跑起來,再用 Nginx 做一下反向代理和負載均衡就基本 OK 了。

但是呢,缺點也很明顯,現在全部功能都集成在一個工程裏了,一旦版本需要擴展維護、升級迭代的,修改一處地方就要將整個應用全部重新編譯、部署、啓動,牽一髮而動全身。長此以往,系統的維護升級會越來越困難,甚至不斷的推翻重建。

升級!微服務架構

既然單體應用是將全部功能都集成在一個工程裏去編譯部署,那現在只要把功能拆分出來,將每個拆分的模塊作爲一個單獨的服務(即微服務),去獨立部署,這一個個的微服務共同組成整個應用不就好了嗎。

引自維基百科:2014 年,Martin Fowler 與 James Lewis 共同提出了微服務的概念,定義了微服務是由以單一應用程序構成的小服務,自己擁有自己的行程與輕量化處理,服務依業務功能設計,以全自動的方式部署,與其他服務使用 HTTP API 通信。同時服務會使用最小的規模的集中管理 (例如 Docker) 能力,服務可以用不同的編程語言與數據庫等組件實現。

試想一下,一個複雜項目,如果是單體架構,CURD 過程中,分工該怎麼分,就比如很多公共業務,經常每個人都去實現了一遍;項目組有新人加入了,想加個什麼功能,還得有項目全部的代碼才能跑起來測試。😥

而使用微服務架構的話,每個人可以單獨負責自己的模塊,各司其職,模塊之間使用 HTTP RESTful API 進行通信就好了,而且哪個模塊出了問題,也可以快速定位到(背鍋)。

基於以上問題,可以搭建一個簡易的微服務架構,如圖:

微服務該如何劃分

現在知道了微服務架構就是將單體架構拆分成一個個微服務,但是微服務的粒度與邊界劃分該怎麼去設計呢?

解決思路:

DDD (領域驅動設計 Domain-DrivenDesign)可以爲微服務的邊界拆分提供方法論,可以解決微服務的粒度問題。

DDD 可以分爲兩個方面,

戰略模式————多個微服務之間的協作

DDD 中根據問題域,將問題劃分爲領域 / 子域、通用語言、限界上下文和架構風格。

戰術設計————單個微服務中的設計

戰術設計是對限界上下文的具體化和細緻化,涉及具體領域對象的設計,戰術設計的關鍵在於抽象出限界上下文中的領域對象及其關係。

DDD 是一種思想、方法論,它可以分離業務複雜度和技術複雜度,最終目標是高內聚、低耦合。

思考,微服務帶來了什麼問題需要治理

使用微服務架構將應用系統劃分成了很多個微服務,這些數量龐大的微服務實例治理起來存在很多的問題。

1、請求網關

上面搭建的簡易微服務架構方式還存在很大的問題,在之前的單體架構中,客戶端向服務端發起請求時,是會先經過 Nginx 進行處理然後才請求到我們的服務中的,而在現在的微服務架構中將原來的單體應用拆分成了多個微服務應用,如果直接對外暴露這些微服務,會造成以下問題:

①客戶端的需求與每個微服務暴露的細粒度的 API 不匹配(客戶端想要獲取某些數據時,總不能連續去調用多個服務進行組合吧)

②協議問題,微服務之間的調用通常是使用 RPC 消息傳遞協議的,這種協議對 web 調用是不友好的。

應對這些問題,針對服務的入口,微服務的調用需要有一個把關的東西,也就是 API 網關。

引自《微服務:從設計到部署》:API 網關是一個服務器,是系統的單入口點。它類似於面向對象設計模式中的門面(Facade)模式。API 網關封裝了內部系統架構,並針對每個客戶端提供一個定製 API。它還可用於認證、監控、負載均衡、緩存和靜態響應處理。

API 網關負責請求路由、組合和協議轉換。所有客戶端請求首先要通過 API 網關,之後請求被路由到適當的服務。API 網關通常會通過調用多個微服務來處理一個請求並聚合結果。它可以在 Web 協議(如 HTTP 和 WebSocket)和用於內部的非 Web 友好協議之間進行轉換。

API 網關還可以爲每個客戶端提供一個定製 API。它通常會爲移動客戶端暴露一個粗粒度的 API,通過調用各種服務並組合結果,減少了客戶端與應用之間的往返次數,同時簡化了客戶端的代碼。

常見的網關選型有:Nginx、Netflix Zuul、Kong 等。

2、服務註冊與發現

單體服務拆分爲微服務後,如果微服務之間存在調用依賴,就需要得到目標服務的服務地址,也就是微服務治理的 “服務發現”。要完成服務發現,就需要將服務信息存儲到某個載體,載體本身即是微服務治理的 “服務註冊與發現中心”,而存儲到載體的動作即是 “服務註冊”。

服務註冊與發現中心主要有以下的職責:

①管理當前註冊到服務註冊與發現中心的微服務實例元數據信息,包括服務實例的服務名、IP 地址、端口號、服務描述和服務狀態等;

②與註冊到服務註冊與發現中心的微服務實例維持心跳,定期檢查註冊表中的服務實例是否在線,並剔除無效服務實例信息;

③提供服務發現能力,爲服務調用方提供服務提供方的服務實例元數據。

常見的服務註冊與發現組件有:Consul、Etcd、ZooKeeper 等。

3、可觀察性

微服務由於較單體應用有了更多的部署載體,需要對衆多服務間的調用關係、狀態有清晰的掌控。可觀測性就包括了調用拓撲關係、監控(Metrics)、日誌(Logging)、鏈路追蹤(Tracing)等。

Tracing、Logging 和 Metrics 這三者之間存在一定的關係,既可以單獨使用,也可以組合使用。每一個組件都有其側重點,Tracing 用於追蹤具體的請求,繪製調用的拓撲;Logging 則是主動記錄的日誌事件;Metrics 記錄了請求相關的時序數據,通常用於性能統計。在分佈式系統中,這三者通常是組合在一起使用。

常見的組件組合方式爲:Metrics:Prometheus + Logging:ELK + Tracing:Jaeger 。

4、容錯處理

爲了保障分佈式系統的高可用性,微服務還需要進行容錯處理,比如實現熔斷,接口限流和降級等機制。

熔斷指,當一個服務因爲各種原因停止響應時,調用方通常會等待一段時間,然後超時或者收到錯誤返回。如果調用鏈路比較長,可能會導致請求堆積,整條鏈路佔用大量資源一直在等待下游響應。所以當多次訪問一個服務失敗時,應熔斷,標記該服務已停止工作,直接返回錯誤。直至該服務恢復正常後再重新建立連接。

服務降級指,當下遊服務停止工作後,如果該服務並非核心業務,則上游服務應該降級,以保證核心業務不中斷。

限流指,一個服務掛掉後,上游服務或者用戶一般會習慣性地重試訪問。這導致一旦服務恢復正常,很可能因爲瞬間網絡流量過大又立刻掛掉,因此服務需要能夠自我保護——限流。

熔斷,接口限流和降級可以使用服務間斷路器 Hystrix 實現,也可以直接通過 API 網關實現。

5、統一認證與授權

不同微服務承載自身獨有的業務職責,對於業務敏感的微服務,需要對其他服務的訪問進行認證與鑑權。

目前主流的統一認證和授權方式有 OAuth2、分佈式 Session 和 JWT 等。

6、負載均衡

負載均衡指的是在一個集羣中通過某種硬件設備或者軟件算法來選擇集羣中的一臺機器處理當前請求,以達到大量請求的分發到多臺服務器上進行處理,使得所有服務器負載都維持在高效穩定的狀態,以提高系統的吞吐量。此外,多個服務實例組成的服務集羣,消除了單點問題,當某一個服務實例宕機時,負載均衡就不會將請求分發給它,而是轉發給其他正常的服務實例,以此提高整個系統的可用性。

負載均衡常分爲硬件負載均衡、軟件負載均衡和 DNS 負載均衡,其中軟件負載均衡又分爲客戶端負載均衡和服務端負載均衡。

硬件負載均衡,是直接在服務器和外部網絡間安裝負載均衡設備,這種設備通常稱之爲負載均衡器,由於專門的設備完成專門的任務,獨立於操作系統,整體性能得到大量提高,加上多樣化的負載均衡策略,智能化的流量管理,可達到最佳的負載均衡需求,其主要應用在大型服務器集羣中,比如 F5 負載均衡器。

軟件負載均衡,是在服務器的操作系統上安裝負載均衡軟件,從此服務器發出的請求經軟件負載均衡算法路由到後端集羣的某一臺機器上。

DNS 負載均衡,用於地理位置上的負載均衡,比如你的網站在全國範圍內都有海量用戶,那麼當不同用戶訪問網站域名時經過 DNS 判斷返回給不同地理位置的用戶的不同 IP,從而達到就近訪問,流量分擔,提升用戶體驗。

在微服務架構中,負載均衡常見的應用場景爲:

① 基於服務註冊和發現的負載均衡機制

這裏的負載均衡的邏輯是運行在客戶端的,屬於客戶端負載均衡,相比於服務器端負載均衡,它有一個顯著的優點,就是可以一定程度避免單點故障。在客戶端負載均衡中,所有的客戶端節點都有一份自己要訪問的服務端清單,這些清單統統都是從服務註冊中心獲取的。

② API 網關的負載均衡

好多組件,怎麼引入——微服務框架

經過上面,我們知道了微服務架構要去治理所帶來的問題,通常我們需要自行組合各種組件,比如 RPC、負載均衡、熔斷等,因此也誕生了很多微服務框架,比如 Java 的 Spring Cloud,Go 的 Go Kit 、 Go Micro 、Go Zero 和 Go kratos 等。但這些框架和開源組件基本都具有侵入性,需要在業務服務中引入服務治理組件。

非侵入式架構——服務網格

微服務架構實踐主要有侵入式架構和非侵入式架構兩種實現形式。侵入式架構是指服務框架嵌入程序代碼,開發者組合各種組件,實現微服務架構。非侵入式架構則是以代理的形式與應用程序部署在一起,代理接管應用程序的網絡且對應用程序透明,這時開發者只需要關注自身業務即可,這種方式以服務網格(Service Mesh) 爲代表。

服務網格可以理解爲微服務的輔助,核心在於將客戶端 SDK 剝離,以 Proxy 組件方式獨立進程運行,每個服務都額外部署這個 Proxy 組件,所有出站入站的流量都通過該組件進行處理和轉發。這個組件被稱爲 Sidecar(邊車模式,類似連接到摩托車的邊車),Sidecar 邊車應用與父應用程序共享相同的生命週期,與父應用程序一起創建和退出。

Sidecar 只負責網絡通信。還需要有個組件來統一管理所有 sidecar 的配置。在 Service Mesh 中,負責配置管理的部分叫控制平面(control plane),負責網絡通信的部分叫數據平面(data plane)。數據平面和控制平面構成了 Service Mesh 的基本架構。如圖:

常見服務網格開源項目有 Istio 、Envoy 、 Linkerd 等。

參考資料:

https://www.cnblogs.com/xishuai/p/microservices-and-service-mesh.html

https://www.cnblogs.com/skabyy/p/11396571.html

https://sq.163yun.com/blog/article/404438199148974080

https://www.toutiao.com/i6896289132050547207/

https://www.jianshu.com/p/dd818114ab4b

https://cloud.tencent.com/developer/article/1593724

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