我們先認識一下SpringCloud的各個組件,然后知其所以然,
原理講解前,先看一個最經典的業務場景,如開發一個電商網站,要實作支付訂單的功能,流程如下:
- 創建一個訂單之后,如果用戶立刻支付了這個訂單,我們需要將訂單狀態更新為“已支付”
- 扣減相應的商品庫存
- 通知倉儲中心,進行發貨
- 給用戶的這次購物增加相應的積分
如上,微服務的應用場景和核心競爭力:
- 降低耦合:每一個微服務專注于單一功能,并通過定義良好的介面清晰表述服務邊界,由于體積小、復雜度低,每個微服務可由一個小規模開發團隊完全掌控,易于保持高可維護性和開發效率,
- 獨立部署:由于微服務具備獨立的運行行程,所以每個微服務也可以獨立部署,當某個微服務發生變更時無需編譯、部署整個應用,由微服務組成的應用相當于具備一系列可并行的發布流程,使得發布更加高效,同時降低對生產環境所造成的風險,最終縮短應用交付周期,
- 選型靈活:微服務架構下,技術選型是去中心化的,每個團隊可以根據自身服務的需求和行業發展的現狀,自由選擇最適合的技術堆疊,由于每個微服務相對簡單,故需要對技術堆疊進行升級時所面臨的風險就較低,甚至完全重構一個微服務也是可行的,
- 容錯機制:當某一組建發生故障時,在單一行程的傳統架構下,故障很有可能在行程內擴散,形成應用全域性的不可用,在微服務架構下,故障會被隔離在單個服務中,若設計良好,其他服務可通過重試、平穩退化等機制實作應用層面的容錯,
- 靈活擴展:單塊架構應用也可以實作橫向擴展,就是將整個應用完整的復制到不同的節點,當應用的不同組件在擴展需求上存在差異時,微服務架構便體現出其靈活性,因為每個服務可以根據實際需求獨立進行擴展,
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實作思路:
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更加“專業”,因為注冊服務更重要的是可用性,我們可以接受短期內達不到一致性的狀況,
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中都是采用本地負載均衡,
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:通過介面獲取資料、并依據此資料初始化自己的應用,
總結如下
寫在最后
歡迎大家關注我的公眾號【風平浪靜如碼】,海量Java相關文章,學習資料都會在里面更新,整理的資料也會放在里面,
覺得寫的還不錯的就點個贊,加個關注唄!點關注,不迷路,持續更新!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/245946.html
標籤:Java
