天天看點

我把 Spring Cloud 給拆了,帶你詳細了解各元件原理!你一定能明白

前言

我們先認識一下SpringCloud的各個元件,然後知其是以然。

我把 Spring Cloud 給拆了,帶你詳細了解各元件原理!你一定能明白

image

原理講解前,先看一個最經典的業務場景,如開發一個電商網站,要實作支付訂單的功能,流程如下:

  1. 建立一個訂單之後,如果使用者立刻支付了這個訂單,我們需要将訂單狀态更新為“已支付”
  2. 扣減相應的商品庫存
  3. 通知倉儲中心,進行發貨
  4. 給使用者的這次購物增加相應的積分
我把 Spring Cloud 給拆了,帶你詳細了解各元件原理!你一定能明白

image

如上,微服務的應用場景和核心競争力:

  • 降低耦合:每一個微服務專注于單一功能,并通過定義良好的接口清晰表述服務邊界。由于體積小、複雜度低,每個微服務可由一個小規模開發團隊完全掌控,易于保持高可維護性和開發效率。
  • 獨立部署:由于微服務具備獨立的運作程序,是以每個微服務也可以獨立部署。當某個微服務發生變更時無需編譯、部署整個應用。由微服務組成的應用相當于具備一系列可并行的釋出流程,使得釋出更加高效,同時降低對生産環境所造成的風險,最終縮短應用傳遞周期。
  • 選型靈活:微服務架構下,技術選型是去中心化的。每個團隊可以根據自身服務的需求和行業發展的現狀,自由選擇最适合的技術棧。由于每個微服務相對簡單,故需要對技術棧進行更新時所面臨的風險就較低,甚至完全重構一個微服務也是可行的。
  • 容錯機制:當某一組建發生故障時,在單一程序的傳統架構下,故障很有可能在程序内擴散,形成應用全局性的不可用。在微服務架構下,故障會被隔離在單個服務中。若設計良好,其他服務可通過重試、平穩退化等機制實作應用層面的容錯。
  • 靈活擴充:單塊架構應用也可以實作橫向擴充,就是将整個應用完整的複制到不同的節點。當應用的不同元件在擴充需求上存在差異時,微服務架構便展現出其靈活性,因為每個服務可以根據實際需求獨立進行擴充。
我把 Spring Cloud 給拆了,帶你詳細了解各元件原理!你一定能明白

image

Dubbo對标Spring Cloud微服務:

  • 背景分析:Dubbo,是阿裡巴巴服務化治理的核心架構,并被廣泛應用于中國各網際網路公司;Spring Cloud是知名的Spring家族的産品。阿裡巴巴是一個商業公司,雖然也開源了很多的頂級的項目,但從整體戰略上來講,仍然是服務于自身的業務為主。Spring專注于企業級開源架構的研發,不論是在中國還是在世界上使用都非常廣泛,開發出通用、開源、穩健的開源架構就是他們的主業。
  • 活躍度對比:Dubbo是一個非常優秀的服務治理架構,并且在服務治理、灰階釋出、流量分發這方面做的比Spring Cloud還好,除過當當網在基礎上增加了rest支援外,已有兩年多的時間幾乎都沒有任何更新了。在使用過程中出現問題,送出到GitHub的Issue也少有回複。相反Spring Cloud自從發展到現在,仍然在不斷的高速發展,從GitHub上送出代碼的頻度和釋出版本的時間間隔就可以看出,現在Spring Cloud即将釋出2.0版本,到了後期會更加完善和穩定。
  • 平台架構:Dubbo架構隻是專注于服務之間的治理,如果我們需要使用配置中心、分布式跟蹤這些内容都需要自己去內建,這樣無形中使用Dubbo的難度就會增加。Spring Cloud幾乎考慮了服務治理的方方面面,更有Spring Boot這個大将的支援,開發起來非常的便利和簡單。
  • 技術前景:Dubbo在各中小公司也從中受益不少。經過了這麼多年的發展,網際網路行業也是湧現了更多先進的技術和理念,Dubbo有點可惜。Spring 推出Spring Boot/Cloud也是因為自身的很多原因。Spring最初推崇的輕量級架構,随着不斷的發展也越來越龐大,随着內建項目越來越多,配置檔案也越來越混亂,慢慢的背離最初的理念。随着這麼多年的發展,微服務、分布式鍊路跟蹤等更多新的技術理念的出現,Spring急需一款架構來改善以前的開發模式,是以才會出現Spring Boot/Cloud項目,我們現在通路Spring官網,會發現Spring Boot和Spring Cloud已經放到首頁最重點突出的三個項目中的前兩個,可見Spring對這兩個架構的重視程度。Dubbo實作如下:

Spring Cloud實作思路:

我把 Spring Cloud 給拆了,帶你詳細了解各元件原理!你一定能明白

image

Eureka

原理:主管服務注冊與發現,也就是微服務的名稱注冊到Eureka,就可以通過Eureka找到微服務,而不需要修改服務調用的配置檔案。

分析:Spring Cloud封裝了Netflix公司開發的Eureka子產品來實作服務的注冊與發現,采用的c-s的設計架構,Eureka Server作為服務注冊功能的伺服器,他是服務注冊中心。而系統的其他微服務,使用Eureka的用戶端連接配接到Eureka Server并維持心跳。這樣系統的維護人員可以通過Eureka Server來監控系統中的各個微服務是否正常運作。Spring Cloud的一些其他子產品(比如Zuul)就可以通過Eureka Server來發現系統其他的微服務,并執行相關邏輯。

Eureka Server

Eureka Server提供服務注冊服務,各個節點啟動後,會在Eureka Server中進行注冊, 這樣Eureka Server中的服務系統資料庫中将會存儲所有可用服務節點的資訊,服務節點的資訊可以在界面中直覺的看到。

Eureka Client

Eureka Client是一個Java用戶端, 用于簡化Eureka Server的互動,用戶端同時也具備一個内置的、 使用輪詢(round-robin)負載算法的負載均衡器。在應用啟動後,将會向Eureka Server發送心跳(預設周期為30秒),以證明目前服務是可用狀态。如果Eureka Server在一定的時間(預設90秒)未收到用戶端的心跳,Eureka Server将會從服務系統資料庫中把這個服務節點移除。

Eureka Server的自我保護機制

如果在15分鐘内超過85%的節點都沒有正常的心跳,那麼Eureka就認為用戶端與注冊中心出現了網絡故障,此時會出現以下幾種情況:

  • Eureka不再從注冊清單中移除因為長時間沒收到心跳而應該過期的服務
  • Eureka仍然能夠接受新服務的注冊和查詢請求,但是不會被同步到其它節點上(即保證目前節點依然可用)
  • 當網絡穩定時,目前執行個體新的注冊資訊會被同步到其它節點中

是以, Eureka可以很好的應對因網絡故障導緻部分節點失去聯系的情況,而不會像ZooKeeper那樣使整個注冊服務癱瘓。

Eureka和ZooKeeper

著名的CAP理論指出,一個分布式系統不可能同時滿足C(一緻性)、A(可用性)和P(分區容錯性)。由于分區容錯性在是分布式系統中必須要保證的,是以我們隻能在A和C之間進行權衡。

ZooKeeper保證CP

當向注冊中心查詢服務清單時,我們可以容忍注冊中心傳回的是幾分鐘以前的注冊資訊,但不能接受服務直接down掉不可用。也就是說,服務注冊功能對可用性的要求要高于一緻性。但是ZooKeeper會出現這樣一種情況,當Master節點因為網絡故障與其他節點失去聯系時,剩餘節點會重新進行leader選舉。問題在于,選舉leader的時間太長,30 ~ 120s,且選舉期間整個ZooKeeper叢集都是不可用的,這就導緻在選舉期間注冊服務癱瘓。在雲部署的環境下,因網絡問題使得ZooKeeper叢集失去Master節點是較大機率會發生的事,雖然服務能夠最終恢複,但是漫長的選舉時間導緻的注冊長期不可用是不能容忍的。

Eureka保證AP

Eurek在設計時就優先保證可用性。Eureka各個節點都是平等的,幾個節點挂掉不會影響正常節點的工作,剩餘的節點依然可以提供注冊和查詢服務。而Eureka的用戶端在向某個Eureka注冊或時如果發現連接配接失敗,則會自動切換至其它節點,隻要有一台Eureka還在,就能保證注冊服務可用(保證可用性),隻不過查到的資訊可能不是最新的(不保證強一緻性)。

除此之外,Eureka還有一種自我保護機制,見上。

總結

Eureka可以很好的應對因網絡故障導緻部分節點失去聯系的情況,而不會像ZooKeeper那樣使整個注冊服務癱瘓。

Eureka作為單純的服務注冊中心來說要比ZooKeeper更加“專業”,因為注冊服務更重要的是可用性,我們可以接受短期内達不到一緻性的狀況。

我把 Spring Cloud 給拆了,帶你詳細了解各元件原理!你一定能明白

image

Ribbon和Feign

在微服務架構中,業務都會被拆分成一個獨立的服務,服務與服務的通訊是基于HTTP RESTful的。Spring Cloud有兩種服務調用方式,一種是Ribbon+RestTemplate,另一種是Feign。

概念

基于Netflix Ribbon用過輪詢政策實作的一套用戶端負載均衡的工具。

用戶端負載均衡:負載均衡Zuul網關将一個請求發送給某一個服務的應用的時候,如果一個服務啟動了多個執行個體,就會通過Ribbon來通過一定的負載均衡政策來發送給某一一個服務執行個體。Spring Cloud中的Ribbon,用戶端會有一個伺服器位址清單,在發送請求前通過負載均衡算法(如簡單輪詢,随機連接配接等)選擇一個伺服器,然後進行通路。

負載均衡

  • 負載均衡:用于将工作負載分布到多個伺服器來提高網站、應用、資料庫或其他服務的性能和可靠性。
  • 使用負載均衡帶來的好處很明顯:當叢集裡的1台或者多台伺服器down的時候,剩餘的沒有down的伺服器可以保證服務的繼續使用;将通路壓力配置設定到各個伺服器,不會由于某一高峰時刻導緻系統cpu急劇上升。
  • 負載均衡有好幾種實作政策,常見的有:随機(Random),輪詢(RoundRobin),一緻性哈希(ConsistentHash),哈希(Hash),權重(Weighted)
  • Ribbon的預設政策是輪詢

RestTemplate

傳統情況下在Java代碼裡通路RESTful服務,一般使用Apache的HttpClient,不過此種方法使用起來太過繁瑣。Spring提供了一種簡單便捷的模闆類來進行操作,這就是RestTemplate。

Feign是一個聲明式http用戶端。使用Feign能讓編寫http用戶端更加簡單,它的使用方法是定義一個接口,然後在上面添加注解,避免了調用目标微服務時,需要不斷的解析/封裝json資料的繁瑣。Spring Cloud中Feign預設內建了Ribbon,并和Eureka結合,預設實作了負載均衡的效果。

Ribbon和Feign的差別

Feign目标****使****編寫Java Http用戶端變得更容易

在使用Ribbon+ RestTemplate時,Ribbon需要自己建構http請求,模拟http請求然後使用RestTemplate發送給其他服務,步驟相當繁瑣。利用RestTemplate對http請求的封裝處理,形成了-套模版化的調用方法。但是在實際開發中,由于對服務依賴的調用可能不止一處,往往一個接口會被多處調用,是以通常都會針對每個微服務自行封裝一些用戶端類來包裝這些依賴服務的調用。是以,Feign在此基礎上做了進一步封裝,由他來幫助我們定義和實作依賴服務接口的定義。

在Feign的實作下,我們隻需建立一個接口并使用注解的方式來配置它(以前是Dao接口上面标注Mapper注解,現在是一個微服務接口上面标注一個Feign注解即可), 即可完成對服務提供方的接口綁定,簡化了使用Spring Cloud Ribbon時,自動封裝服務調用用戶端的開發量。

Feign內建了Ribbon

Ribbon通過輪詢實作了用戶端的負載均衡,而與Ribbon不同的是,Feign是一個聲明式的Web服務用戶端, 使得編寫Web服務用戶端變得非常容易,隻需要建立一個接口, 然後在上面添加注解,像調用本地方法一樣調用它就可以,而感覺不到是調用遠端方法。SpringCloud中Feign預設內建了Ribbon,并和Eureka結合,預設實作了負載均衡的效果。

Ribbon和Nginx的差別

伺服器端負載均衡Nginx

Nginx是用戶端所有請求統一交給Nginx,由Nginx進行實作負載均衡請求轉發,屬于伺服器端負載均衡。既請求由Nginx伺服器端進行轉發。用戶端負載均衡Ribbon,Ribbon是從Eureka注冊中心伺服器端上擷取服務注冊資訊清單,緩存到本地,然後在本地實作輪詢負載均衡政策。既在用戶端實作負載均衡。

應用場景的差別

Nginx适合于伺服器端實作負載均衡,比如:Tomcat,Ribbon适合與在微服務中RPC遠端調用實作本地服務負載均衡,比如:Dubbo、Spring Cloud中都是采用本地負載均衡。

我把 Spring Cloud 給拆了,帶你詳細了解各元件原理!你一定能明白

image

Zuul

應用場景

假如目前有十幾個微服務服務,訂單,商品,使用者等等,顯然是用戶端不需要和每個服務逐一打交道,這就需要有一個統一入口,它就是服務網關。API網關所有的用戶端請求通過這個網關通路背景的服務。他可以使用一定的路由配置來判斷某一個URL由哪個服務來處理。并從Eureka擷取注冊的服務來轉發請求。

核心功能

Zuul包含了對請求的路由和過濾兩個最主要的功能,是各種服務的統一入口,同時還會用來提供監控、授權、安全、排程等等。

路由功能:負責将外部請求轉發到具體的微服務執行個體上,是實作外部通路統一入口的基礎。

過濾器功能:則負責對請求的處理過程進行幹預,是實作請求校驗、服務聚合等功能的基礎。

Zuul和Eureka進行整合:将Zuul自身注冊為Eureka服務治理下的應用,同時從Eureka中獲得其他微服務的消息,也即以後的通路微服務都是通過Zuul跳轉後獲得。

注意:Zuul服務最終還是會注冊進Eureka,提供代理+路由+過濾三大功能。

核心原理

Zuul的核心是一系列的filters,其作用可以類比Servlet架構的Filter,或者AOP。

過濾器之間沒有直接進行通信,而是通過Request Context(上下文)進行資料傳遞。

Zuul的過濾器是由Groovy寫成,這些過濾器檔案被放在Zuul Server上的特定目錄下面,Zuul會定期輪詢這些目錄,修改過的過濾器會動态的加載到Zuul Server中以便過濾請求使用。

Zuul負載均衡:Zuul攔截對應的API字首請求做轉發,轉發到對應的serverId上,在Eureka服務上同一個serverId可以對應多個服務,也就是說用同一個服務節點不同的端口注冊兩個執行個體,但是serverId是一樣Zuul做轉發的時候會結合eureka-server起到負載均衡的效果。

過濾器的種類:

  • PRE(前置):這種過濾器在請求被路由之前調用。我們可利用這種過濾器實作鑒權、限流、參數校驗調整等。
  • ROUTING(路由):這種過濾器将請求路由到微服務。這種過濾器用于建構發送給微服務的請求,并使用Apache HttpClient或Netfilx Ribbon請求微服務。
  • POST(後置):這種過濾器在路由到微服務以後執行。這種過濾器可用來為響應添加标準的HTTP Header、收集統計資訊和名額、将響應從微服務發送給用戶端、日志等。
  • ERROR(錯誤):在其他階段發生錯誤時執行該過濾器。

Zuul和Nginx

Zuul雖然在性能上和Nginx沒法比,但它也有它的優點。Zuul提供了認證鑒權,動态路由,監控,彈性,安全,負載均衡等邊緣服務,在團隊規模不大的情況下,沒有專門負責路由開發時,使用Zuul當網關是一個快速上手的好方案。

Nginx和Zuul是可以配合使用的,發揮各自的優點,使用Nginx作為負載均衡實作高并發的請求轉發,Zuul用作網關。

Zuul和Ribbon實作負載均衡

Zuul支援Ribbon和Hystrix,也能夠實作用戶端的負載均衡。我們的Feign不也是實作用戶端的負載均衡和Hystrix的嗎?既然Zuul已經能夠實作了,那我們的Feign還有必要嗎?

可以這樣了解:

Zuul是對外暴露的唯一接口相當于路由的是controller的請求,而Ribbonhe和Fegin路由了service的請求。

Zuul做最外層請求的負載均衡,而Ribbon和Fegin做的是系統内部各個微服務的service的調用的負載均衡。

Hystrix

介紹

Hystrix是一個用于處理分布式系統的延遲和容錯的開源庫,在分布式系統裡,許多依賴不可避兔的會調用失敗,比如逾時、異常等,Hystrix能夠保證在一個依賴出問題的情況下,不會導緻整體服務失敗,避免級聯故障,以提高分布式系統的彈性。Hystrix的出現就是為了解決雪崩效應。

服務雪崩

多個微服務之間調用的時候,假設微服務A調用微服務B和微服務C,微服務B和微服務C又調用其它的微服務,這就是所謂的“扇出”。如果扇出的鍊路上某個微服務的調用響應時間過長或者不可用,對微服務A的調用就會占用越來越多的系統資源,進而引起系統崩潰,所謂的”雪崩效應”。

服務熔斷

熔斷機制是應對雪崩效應的一種微服務鍊路保護機制。

當删除鍊路的某個微服務不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的調用,快速傳回”錯誤的響應資訊。當檢測到該節點微服務調用響應正常後恢複調用鍊路。在SpringCloud架構裡熔斷機制通過Hystrix實作。Hystrix會監控微服務間調用的狀況,當失敗的調用到一定門檻值,預設是5秒内20次調用失敗就會啟動熔斷機制。熔斷機制的注解是@HystrixCommand。

服務降級

整體資源快不夠了,忍痛将某些服務先關掉,待渡過難關,再開啟回來。

Hystrix監控和斷路器

我們隻需要在服務接口上添加Hystrix标簽,就可以實作對這個接口的監控和斷路器功能。

Hystrix Dashboard監控面闆,提供了一個界面,可以監控各個服務上的服務調用所消耗的時間等。

Hystrix Turbine監控聚合

使用Hystrix監控,我們需要打開每一個服務執行個體的監控資訊來檢視。而Turbine可以幫助我們把所有的服務執行個體的監控資訊聚合到一個地方統檢視。這樣就不需要挨個打開一個個的頁面一個個檢視。

Zuul的安全機制

簽名機制,為防止接口資料篡改和重複調用,增加接口參數校驗機制,sig簽名算法為MD5(appKey+appSecret+timestamp),appKey是配置設定給用戶端的ID,appSecret是配置設定給用戶端的密鑰,timestamp為unix時間戳,請求的URL有效時間為15分鐘。

Token機制,使用者在登入之後會傳回一個access_ token,用戶端在通路需要登入之後才能通路的資源,需要在在Authorization頭部使用Bearer模式新增token,如head(“Authorization”,” Bearer token”)。

Hystrix的設計原則

  • 資源隔離(線程池隔離和信号量隔離)機制:限制調用分布式服務的資源使用,某一個調用的服務出現問題不會影響其它服務調用。
  • 限流機制:限流機制主要是提前對各個類型的請求設定最高的QPS門檻值,若高于設定的門檻值則對該請求直接傳回,不再調用後續資源。
  • 熔斷機制:當失敗率達到閥值自動觸發降級(如因網絡故障、逾時造成的失敗率真高),熔斷器觸發的快速失敗會進行快速恢複。
  • 降級機制:逾時降級、資源不足時(線程或信号量)降級、運作異常降級等,降級後可以配合降級接口傳回托底資料。
  • 緩存支援:提供了請求緩存、請求合并實作。
  • 通過近實時的統計/監控/報警功能,來提高故障發現的速度。
  • 通過近實時的屬性和配置熱修改功能,來提高故障處理和恢複的速度。

Config

介紹

Spring Cloud Config是一個解決分布式系統的配置管理方案。微服務意味着要将單體應用中的業務拆分成一個個子服務,每個服務的粒度相對較小,是以系統 中會出現大量的服務。由于每個服務都需要必要的配置資訊才能運作,是以一套集中式的、 動态的配置管理設施是必不可少的。Spring Cloud提供了ConfigServer來解決這個問題,我們每一個微服務自 己帶着一個application.yml 上百個配置檔案的管理。

應用場景

  • 不友善維護,多人同時對配置檔案進行修改,沖突不斷,很難維護
  • 配置内容安全和權限,主要是針對線上的配置來說,一般不對開發公開,隻有運維有權限是以需要将配置檔案隔離,不放到項目代碼裡
  • 更新配置項目需要重新開機,每次更新配置檔案都需要重新開機項目,很耗時。使用了配置中心後,即可實作配置實時更新congfig Server和Config Client結合Spring Cloud Bus實作配置自動重新整理。

原理

  • 配置檔案存儲在遠端Git(比如GitHub,Gitee等倉庫),config-server從遠端Git拉取配置檔案,并儲存到本地Git。
  • 本地Git和config-server的互動是雙向的,因為當遠端Git無法通路時,會從本地Git擷取配置檔案。
  • config-client(即各個微服務),從config-server拉取配置檔案。

角色

  • Config Server:提供配置檔案的存儲、以接口的形式将配置檔案的内容提供出去。
  • Config Client:通過接口擷取資料、并依據此資料初始化自己的應用。

總結如下