從 0 開始學微服務

說起微服務,大家應該並不陌生,不只是一線大廠,很多中小規模團隊也已經將這項技術引入並在實際業務中落地。

那作爲一名開發人員,應該如何學習微服務呢?

雖然現在開源的微服務框架有很多,各種編程語言的都有,花上幾個小時搭建一套可運行的開發環境也並不是一件難事。但畢竟微服務涉及的組件還是挺多的,相比於單體架構來說,複雜度提升了不少。

不知道你有沒有和我一樣的困擾,有時候想要深入學習一下,但卻不知道從什麼地方入手,結果就是對其瞭解只是浮於表面。

所以我最近看了極客時間的專欄《從 0 開始學微服務》,覺得作爲入門還是不錯的。

同時,我總結了專欄中的部分內容,並加入一些自己的思考,形成了這篇文章。算是學習微服務的一個大綱,然後再按照這個大綱去深入學習,不斷充實這套技術體系。

好了,下面正文開始。

什麼是微服務

微服務是指開發應用所用的一種架構形式。通過微服務,可將大型應用分解成多個獨立的組件,其中每個組件都有各自的責任領域。在處理一個用戶請求時,基於微服務的應用可能會調用許多內部微服務來共同生成其響應。

微服務的特點:

  1. 服務拆分粒度: 小到一個子模塊,只要該模塊依賴的資源與其他模塊都沒有關係,那麼就可以拆分爲一個微服務。

  2. 服務獨立部署: 每個微服務都嚴格遵循獨立打包部署的準則,互不影響。比如一臺物理機上可以部署多個 Docker 實例,每個 Docker 實例可以部署一個微服務的代碼。

  3. 服務獨立維護: 每個微服務都可以交由一個小團隊甚至個人來開發、測試、發佈和運維,並對整個生命週期負責。

  4. 服務治理能力要求高: 因爲拆分爲微服務之後,服務的數量變多,因此需要有統一的服務治理平臺,來對各個服務進行管理。

服務發佈和引用

想要構建微服務,首先要解決的問題是,服務提供者如何發佈一個服務,服務消費者如何引用這個服務。具體來說,就是這個服務的接口名是什麼?調用這個服務需要傳遞哪些參數?接口的返回值是什麼類型?以及一些其他接口描述信息。

最常見的服務發佈和引用的方式有三種:

RESTful API

這種方式就比較常見了,主要被用作 HTTP 或者 HTTPS 協議的接口定義,即使在非微服務架構體系下,也被廣泛採用。而且學習成本低,比較適合用作跨業務平臺之間的服務協議。

XML 配置

這種方式下需要在服務提供者和服務消費者之間維持一份對等的 XML 配置文件,來保證服務調用。比如提供者維護 server.xml,消費者維護 client.xml。

在接口變更時,需要同時修改這兩個接口描述文件。

IDL 文件

IDL 就是接口描述語言(interface description language)的縮寫,通過一種中立的方式來描述接口,使得在不同的平臺上運行的對象和不同語言編寫的程序可以相互通信交流。

也就是說 IDL 主要是用作跨語言平臺的服務之間的調用,有兩種最常用的 IDL:一個是 Facebook 開源的 Thrift 協議,另一個是 Google 開源的 gRPC 協議。

小結

每種方式都有各自的優缺點,具體應該如何選擇,需要根據自身的業務特點。

V6bT4x

註冊中心

服務拆分之後,服務的提供者和消費者分別運行在不同的機器上,而且服務衆多,有幾十個,甚至上百個。這就涉及到一個問題,消費者如何才能找到服務提供者,這也是註冊中心需要解決的問題。

註冊中心需要實現哪些 API?

除此之外,爲了便於管理,註冊中心還必須提供一些後臺管理的 API,例如:

配置中心

在拆分爲微服務架構前,單體應用只需要管理一套配置;而拆分爲微服務後,每一個系統都有自己的配置,並且都各不相同,而且因爲服務治理的需要,有些配置還需要能夠動態改變,以達到動態降級、切流量、擴縮容等目的,所以如何管理配置十分重要。

配置中心一般包含下面幾個功能:

API 網關

API 網關可以被視爲一種充當應用程序服務和不同客戶端之間的中間件,可以管理許多事情,例如:

事實上,它是作爲一個反向代理工作的,客戶端只需要知道系統的網關,應用服務就可以隱藏起來,不直接向其他系統暴露。

如果沒有 API 網關,可能需要在每個服務中做一些橫切關注點,比如想記錄服務的請求和響應。此外,如果應用程序由多個服務組成,客戶端需要知道每個服務地址,並且在更改服務地址的情況下,需要更新多個地方。

負載均衡

微服務架構擁有很好的可擴展性,我們能夠通過運行更多服務實例來處理更多請求,但問題是,哪個實例應該接收請求,或客戶端如何知道哪個服務實例應該處理請求?

這些問題的答案是負載均衡。負載均衡是高可用網絡基礎架構的關鍵組件,通常用於將工作負載分佈到多個服務器來提高網站、應用、數據庫或其他服務的性能和可靠性。

常用的負載均衡算法有一下五種:

隨機算法

顧名思義就是從可用的服務節點中,隨機挑選一個節點來訪問。

實現比較簡單,在請求量遠超可用服務節點數量的情況下,各個服務節點被訪問的概率基本相同,主要應用在各個服務節點的性能差異不大的情況下。

輪詢算法

跟隨機算法類似,各個服務節點被訪問的概率也基本相同,也主要應用在各個服務節點性能差異不大的情況下。

加權輪詢算法

在輪詢算法基礎上的改進,可以通過給每個節點設置不同的權重來控制訪問的概率,因此主要被用在服務節點性能差異比較大的情況。

比如經常會出現一種情況,因爲採購時間的不同,新的服務節點的性能往往要高於舊的節點,這個時候可以給新的節點設置更高的權重,讓它承擔更多的請求,充分發揮新節點的性能優勢。

最少活躍連接算法

與加權輪詢算法預先定義好每個節點的訪問權重不同,採用最少活躍連接算法,客戶端同服務端節點的連接數是在時刻變化的,理論上連接數越少代表此時服務端節點越空閒,選擇最空閒的節點發起請求,能獲取更快的響應速度。

尤其在服務端節點性能差異較大,而又不好做到預先定義權重時,採用最少活躍連接算法是比較好的選擇。

一致性 hash 算法

因爲它能夠保證同一個客戶端的請求始終訪問同一個服務節點,所以適合服務端節點處理不同客戶端請求差異較大的場景。

比如服務端緩存裏保存着客戶端的請求結果,如果同一客戶端一直訪問一個服務節點,那麼就可以一直從緩存中獲取數據。

服務監控

不管是單體架構,還是微服務架構,監控都是必不可少的。只不過微服務架構更加複雜,監控起來也就更加不容易。

對於一個微服務來說,必須明確要監控哪些對象、哪些指標,並且還要從不同的維度進行監控,才能掌握微服務的調用情況。

監控對象

監控對象可以分爲四個層次,由上到下可歸納爲:

監控指標

搞清楚要監控的對象之後,需要監控具體哪些指標呢?

監控維度

一般來說,要從多個維度來對業務進行監控,包括下面幾個維度:

服務追蹤

在調試單體應用時,非常直觀容易。但是在微服務架構上,因爲一個請求可能會通過不同的服務,而不同的服務又不在一個地方,這使得調試和跟蹤變得困難。

所以服務追蹤是分佈式系統中必不可少的功能,它能夠幫助我們查詢一次用戶請求在系統中的具體執行路徑,以及每一條路徑的上下游的詳細情況,對於追查問題十分有用。

它的核心理念就是調用鏈:通過一個全局唯一的 ID 將分佈在各個服務節點上的同一次請求串聯起來,從而還原原有的調用關係,可以追蹤系統問題、分析調用數據並統計各種系統指標。

小結一下,traceId 是用於串聯某一次請求在系統中經過的所有路徑,spanId 是用於區分系統不同服務之間調用的先後關係,而 annotation 是用於業務自定義一些自己感興趣的數據,在上傳 traceId 和 spanId 這些基本信息之外,添加一些自己感興趣的信息。

故障處理

系統故障是避免不了的,雖然微服務架構做了服務拆分,不至於像單體架構那樣整體崩潰,但由於其整體複雜度也大大提升,故障處理也更加困難。

限流

顧名思義,限流就是限制流量。通常情況下,系統能夠承載的流量根據集羣規模的大小是固定的,可以稱之爲系統的最大容量。

當真實流量超過了系統的最大容量後,就會導致系統響應變慢,服務調用出現大量超時,反映給用戶的感覺就是卡頓、無響應。

所以,應該根據系統的最大容量,給系統設置一個閾值,超過這個閾值的請求會被自動拋棄,這樣的話可以最大限度地保證系統提供的服務正常。

熔斷

熔斷和限流還不太一樣,上面我們可以看到限流是控制請求速率,只要還能承受,那麼都會處理,但熔斷不是。

在一條調用鏈上,如果發現某個服務異常,比如響應超時。那麼調用者爲了避免過多請求導致資源消耗過大,最終引發系統雪崩,會直接返回錯誤,而不是瘋狂調用這個服務。

降級

什麼是降級呢?降級就是通過停止系統中的某些功能,來保證系統整體的可用性。

降級可以說是一種被動防禦的措施,爲什麼這麼說呢?因爲它一般是系統已經出現故障後所採取的一種止損措施。

容器化

單體應用拆分成多個微服務後,能夠實現快速開發迭代,但隨之帶來的問題是測試和運維部署成本的提升。

而容器技術正好可以很好的解決這些問題,目前最流行的當屬 Docker 莫屬。

微服務容器化運維主要涉及到以下幾點:

鏡像倉庫

鏡像倉庫的概念其實跟 Git 代碼倉庫類似,就是有一個集中存儲的地方,把鏡像存儲在這裏,在服務發佈的時候,各個服務器都訪問這個集中存儲來拉取鏡像,然後啓動容器。

容器調度

這個階段主要是解決在哪些機器上啓動容器的問題,特別是規模比較大的公司,一般有物理機集羣,虛擬機集羣,私有云和公有云。對接這麼多不同的平臺,難度還是不小的。

需要統一管理來自不同集羣的機器權限管理、成本覈算以及環境初始化等操作,這個時候就需要有一個統一的層來完成這個操作。

很顯然,靠人工是肯定不行的,需要搭建統一的部署運維平臺。

服務編排

大部分情況下,微服務之間是相互獨立的,在進行容器調度的時候不需要考慮彼此。

但有時候也會存在一些場景,比如服務 A 調度的前提必須是先有服務 B,這樣的話就要求在進行容器調度的時候,還需要考慮服務之間的依賴關係。

Service Mesh

Service Mesh 的概念最早是由 Buoyant 公司的 CEO William Morgan 提出,他給出的服務網格的定義是:

A service mesh is a dedicated infrastructure layer for handling service-to-service communication. It’s responsible for the reliable delivery of requests through the complex topology of services that comprise a modern, cloud native application. In practice, the service mesh is typically implemented as an array of lightweight network proxies that are deployed alongside application code, without the application needing to be aware.

被很多人定義爲下一代的微服務架構。

目前,Service Mesh 的代表產品當屬 Google 和 IBM 的 lstio。

Istio 的架構可以說由兩部分組成,分別是 Proxy 和 Control Plane。

參考資料:

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