SpringCloud框架全解析,繼續你的微服務之旅,直達成功彼岸 寫在前面 註冊中心 Eureka 介紹 服務發現 負載均衡 Feign 微服務容錯 雪崩的形成 Hystrix

寫在前面

Spring Cloud是一系列框架的有序集合, 它利用Spring Boot的開發便利性巧妙地簡化了分佈式系統基礎設施的開發,如服務發現註冊、配置中心、消息總線、負載均衡、斷路器、數據監控等,都可以用SpringBoot的開發風格做到一鍵啓動和部署。

Spring Cloud微服務工具包爲開發者提供了分佈式系統中的配置管理、服務發現、斷路器、智能路由、微代理、控制總線等開發工具包。它的各個項目基於Spring Boot,將Netlix的多個框架進行封裝,並且通過自動配置的方式將這些框架綁定到Spring的環境中,從而簡化了這些框架的使用。

各組件的運行流程如下:

所有請求都統一通過API網關(Zuul)來訪問內部服務。

網關接收到請求後,從註冊中心(Eureka) 獲取可用服務。

由Ribbon進行均衡負載後,分發到後端的具體實例。

微服務之間通過Feign進行通信處理業務。

Hystrix負責處理服務超時熔斷。

Turbine監控服務間的調用和熔斷相關指標。

上面只是Spring Cloud體系的一部分, Spring Cloud共集成了19 個子項目,裏面都包含一個或者多個第三方的組件或框架。

Spring Cloud工具框架如下。

Spring Cloud Config:配置中心,利用Git集中管理程序的配置。

Spring Cloud Netflix:集成衆多Netlix的開源軟件。

Spring Cloud Bus:消息總線,利用分佈式消息將服務和服務實例連接在一起,用於在一個集羣中傳播狀態的變化。

Spring Cloud for Cloud Foundry:利用Pivotal Cloudfoundry集成應用程序。

Spring Cloud Foundry Service Broker:爲建立管理雲託管服務的服務代理提供了一個起點。

Spring Cloud Cluster:基於ZooKeeper、Redis、 Hazelcast、 Consul實現的領導選舉和平民狀態模式的抽象和實現。

Spring Cloud Consul:基於Hashicorp Consul實現的服務發現和配置管理。

SpringCloudSecurity:在Zuul代理中爲OAuth2REST客戶端和認證頭轉發提供負載均衡。

Spring Cloud Sleuth:應用的分佈式追蹤系統和Zipkin、HTrace、 ELK兼容。

Spring Cloud Data Flow:一個雲本地程序和操作模型,在一個結構化的平臺上組成數據微服務。

Spring Cloud Stream:基於Redis、RabbitMQ、 Kafka 實現的消息微服務,簡單聲明模型用於在Spring Cloud應用中收發消息。

Spring Cloud Stream App Starters:基於Spring Boot爲外部系統提供Spring的集成。

Spring Cloud Task:短生命週期的微服務,爲Spring Boot應用簡單聲明添加功能和非功能特性。

Spring Cloud Task:任務調度框架。

Spring Cloud ZooKeeper:服務發現和配置管理基於Apache ZooKeeper。

Spring Cloud for Amazon Web Services:快速和亞馬遜網絡服務集成。

Spring Cloud Connectors:便於PaaS應用在各種平臺上連接到後端數據庫和消息經紀服務。

Spring Cloud Starters:項目已經終止並且在Angel.SR2後的版本和其他項目合併。

Spring Cloud CLI:基於Spring Cloud CLI,可以以命令行方式快速建立雲組件。

註冊中心

CAP理論指出,一個分佈式系統不可能同時滿足C (一致性)、A (可用性)和P (分區容錯性)。由於分區容錯性在分佈式系統中是必須要保證的,因此我們只能在A和C之間進行權衡。

那麼如何選擇一款適合 自己的註冊中心呢?就讓我們來看一下常用的註冊中心。註冊中心就像是書的目錄,而章節的內容就是具體的實現,當服務之間互相調用時,相當於先通過註冊中心找到對應的目錄,然後去調用相應的實現完成功能。

常用的註冊中心包括ZooKeeper、Eureka、 etcd 和Consul。

ZooKeeper

ZooKeeper是一-種爲分佈式應用所設計的高可用、高性能且一致的開源協調服務,它提供了一項基本服務:分佈式鎖服務。由於ZooKeeper的開源特性,後來開發者在分佈式鎖的基礎上,摸索出了其他的使用方法:配置維護、組服務、分佈式消息隊列、分佈式通知/協調等。ZooKeeper性能上的特點決定了它能夠用在大型的、分佈式的系統當中。從可靠性方面來說,它並不會因爲一個節點的錯誤而崩潰。除此之外,它嚴格的序列訪問控制意味着複雜的控制原語可以應用在客戶端上。

很多場景下ZooKeeper也作爲Service發現服務解決方案。ZooKeeper 保證的是CP,即任何時刻對ZooKeeper的訪問請求能得到一致的數據結果,同時系統對網絡分割具備容錯性,但是它不能保證每次服務請求的可用性。

Eureka

Eureka是Ntlix 開發的服務發現框架,Spring Cloud 將它集成在自己的子項目Spring-cloud-netflix中,實現Spring Cloud的服務發現功能。Eureka Server會提供服務註冊功能,各個服務節點啓動後,會在Eureka Server中進行註冊,這樣Eureka Server中就有了所有服務節點的信息,並且Eureka有監控頁面,可以在頁面中直觀地看到所有註冊的服務的情況。同時Eureka有心跳機制,當某個節點服務在規定時間內沒有發送心跳信號時,Eureka 會從服務註冊表中把這個服務節點移除。

Eureka還提供了客戶端緩存的機制,即使所有的EurekaServer都掛掉,客戶端仍然可以利用緩存中的信息調用服務節點的服務。Eureka一般配合Ribbon進行使用,Ribbon提供了客戶端負載均衡的功能,Ribbon 利用從Eureka中讀取到的服務信息,在調用服務節點提供的服務時,會合理地進行負載。Eureka 遵守的就是AP原則。

etcd

etcd是一個高可用的鍵值存儲系統,主要用於共享配置和服務發現。etcd是由CoreOS開發並維護的,靈感來自ZooKeeper和Doozer, 它使用Go語言編寫,並通過Raft一致性算法處理日誌複製以保證強一致性。Raft 是一個新的一致性算法,適用於分佈式系統的日誌複製,Raft通過選舉的方式來實現一致性。 Google 的容器集羣管理系統Kubernetes、開源PaaS平臺Cloud Foundry和CoreOS的Fleet都廣泛使用了etcd。 在分佈式系統中,如何管理節點間的狀態一直是一個難題,etcd 像是專門爲集羣環境的服務發現和註冊而設計的,它提供了數據TTL失效、數據改變監視、多值、目錄監聽、分佈式鎖原子操作等功能,可以方便地跟蹤並管理集羣節點的狀態。

Consul

Consul 是HashiCorp公司推出的開源工具,用於實現分佈式系統的服務發現與配置共享。對比其他分佈式服務註冊與發現的方案,Consul 的方案更“一站式”,內置了服務註冊與發現框架、分佈--致性協議實現(Raft算法)、健康檢查、Key/Value存儲、多數據中心方案,不再需要依賴其他工具(比如ZooKeeper等)。Consul用Golang 實現,因此具有天然可移植性(支持Linux、Windows和Mac OS X);安裝包僅包含一個可執行文件,方便部署,與Docker等輕量級容器可無縫配合。

在註冊中心的選擇方面,可以針對自身業務的特點,選擇一款合適的註冊中心,如果團隊原有框架基於Dubbo,那麼ZooKeeper會更合適一些;如果團隊整體使用Spring Cloud, 那麼Eureka的優勢就會更大一些,如果團隊對於容器化的要求比較高,那麼etcd和Consul都是不錯的選擇。由於我們的整體構建所需,我們選擇的是Spring Cloud中的Eureka。

Eureka 介紹

Eureka的一些概念如下。

Register: 服務註冊

當Eureka客戶端向Eureka Server 註冊時,它提供自身的元數據,比如IP地址、端口、運行狀況指示符URL、主頁等。

Renew: 服務續約

Eureka客戶會每隔30秒發送一次心跳來續約。 通過續約來告知Eureka Server該Eureka客戶仍然存在,沒有出現問題。正常情況下,如果Eureka Server在90秒後沒有收到Eureka客戶的續約,則它會將實例從其註冊表中刪除。建議不要更改續約間隔。

Fetch Registries:獲取註冊列表信息

Eureka客戶端從服務器獲取註冊表信息,並將其緩存在本地。客戶端會使用該信息查找其他服務,從而進行遠程調用。該註冊列表信息定期(每30秒)更新一次。每次返回的註冊列表信息可能與Eureka客戶端的緩存信息不同,Eureka客戶端會自動處理。如果由於某種原因導致註冊列表信息不能及時匹配,則Eureka客戶端會重新獲取整個註冊表信息。Eureka服務器緩存註冊列表信息,整個註冊表及每個應用程序的信息都進行了壓縮,壓縮內容和沒有壓縮的內容完全相同。Eureka客戶端和Eureka服務器可以使用JSON/XML格式進行通信。在默認的情況下,Eureka客戶端使用壓縮JSON格式來獲取註冊列表的信息。

Cancel: 服務下線

Eureka客戶端在程序關閉時向Eureka服務器發送取消請求。發送請求後,該客戶端實例信息將從服務器的實例註冊表中刪除。該下線請求不會自動完成,它需要調用以下內容:

DiscoveryManager.getInstance() .shutdownComponent() ;

Eviction:服務剔除

在默認的情況下,當Eureka客戶端連續90秒沒有向Eureka服務器發送服務續約(即心跳)時,Eureka服務器會將該服務實例從服務註冊列表刪除,即服務剔除。

Eureka由多個instance ( 服務實例)組成,這些服務實例可以分爲兩種: Eureka Server 和Eureka Client。

Eureka Client再分爲Service Provider和Service Consumer。

Eureka Server:服務的註冊中心,負責維護註冊的服務列表。

Service Provider:服務提供方,作爲一個Eureka Client,向Eureka Server 進行服務註冊、續約和下線等操作,註冊的主要數據包括服務名、機器IP、端口號、域名等。

Service Consumer:服務消費方,作爲一個Eureka Client,向Eureka Server獲取Service Provider的註冊信息,並通過遠程調用與Service Provider進行通信。

Service Provider 和Service Consumer 不是嚴格的概念,Service Consumer 也可以隨時向Eureka Server註冊,來讓自己變成一個Service Provider。

Eureka程序構成如下。

純正的Servlet應用,需構建成war包部署。

使用了Jersey 框架實現自身的RESTful HTTP接口。

peer 之間的同步與服務的註冊全部通過HTTP協議實現。

定時任務(發送心跳、定時清理過期服務、節點同步等)通過JDK自帶的Timer實現。

內存緩存使用Google的guava包實現。

服務發現

在現在的軟件開發中,如果對性能要求不是非常高,則一般使用REST API來開放服務的接口。

服務發現有如下兩種模式。

客戶端服務發現(Client-Side Discovery)如下圖所示。

服務實例啓動時會向服務註冊中心進行註冊,服務的註冊中心能夠看到所有註冊的實例。客戶端需要調用服務時,先到註冊中心摘取可用的服務列表的地址,然後根據負載均衡算法, 去獲取一個可用的實例的地址來響應這次請求。

一個服務實例被啓動,它的網絡地址會被寫到註冊中心,當服務實例終止,會從註冊表中刪除。這個服務實例的註冊表通過心跳機制動態刷新。

服務端服務發現(Server-Side Discovery)如下圖所示。

客戶端通過負載均衡器向某個服務提出請求,負載均衡器向註冊中心發出請求,將每個請求轉發至可用的服務實例。和客戶端發現一樣,服務實例啓動時在註冊中心註冊,當服務實例銷燬時,會從服務註冊表中進行刪除。

使用服務器端服務現,客戶端無須關注發現的細節,只需要簡單地向負載均衡器發送請求即可,實際上減少了編程語言框架需要完成的服務發現邏輯。缺點是除非部署環境能夠提供負載均衡,否則負載均衡器是另外一個需要配置管理的高可用系統功能。目前比較流行的方式是使用Nginx來進行服務器端的負載均衡。

負載均衡

負載均衡是雲計算的基礎組件,是網絡流量的入口,其重要性不言而喻。

什麼是負載均衡呢?用戶輸入的流量通過負載均衡器按照某種負載均衡算法把流量均勻地分散到後端的多個服務器上,接收到請求的服務器可以獨立地響應請求,達到負載分擔的目的。從應用場景上來說,常見的負載均衡模型有全局負載均衡和集羣內負載均衡。

服務端負載均衡

負載均衡是處理高併發、緩解網絡壓力和進行服務端擴容的重要手段之-一,但是一般情況下我們所說的負載均衡通常都是指服務端負載均衡,服務端負載均衡又分爲兩種,一種是硬件負載均衡,另一種是軟件負載均衡。

硬件負載均衡主要通過在服務器節點之間安裝專門用於負載均衡的設備實現,常見的設備如F5。

軟件負載均衡則主要通過在服務器上安裝一些 具有負載均衡功能的軟件來完成請求分發進而實現負載均衡,常見的就是Nginx。

無論是硬件負載均衡還是軟件負載均衡,它的工作原理均如下圖所示。

無論是硬件負載均衡還是軟件負載均衡,都會維護一個可用的服務端清單,然後通過心跳機制來刪除故障的服務端節點以保證清單中都是可以正常訪問的服務端節點。當客戶端的請求到達負載均衡服務器時,負載均衡服務器按照某種配置好的規則從可用服務端清單中選出一臺服務器去處理客戶端的請求,這就是服務端負載均衡。

負載均衡策略:

簡單輪詢負載均衡;

加權響應時間負載均衡;

區域感知輪詢負載均衡;

隨機負載均衡。

Feign

在Spring Cloud Netlix中,各個微服務都是以HTTP接口的形式暴露自身服務的,因此在調用遠程服務時就必須使用HTTP客戶端。我們可以使用JDK原生的URLConnection、Apache的Http Client、Netty 的異步HTTP Client,以及Spring的RestTemplate。但是,用起來最方便、最優雅的還是Feign。

Feign是一種聲明式、模板化的HTTP客戶端。在Spring Cloud中使用Feign,我們可以做到使用HTTP請求遠程服務時能與調用本地方法一樣的編碼體驗,開發者完全感知不到這是遠程方法,更感知不到這是個HTTP請求。

微服務容錯

在大中型分佈式系統中,通常系統有很多依賴。在併發量很小的時候,通常不會造成很嚴重的後果,但是當併發量激增,這些依賴的穩定性就有可能造成整個系統的癱瘓,這也就是我們經常說的雪崩。

雪崩的形成

服務雪崩效應是一種因服務提供者的不可用而導致服務調用者的不可用的現象,並將不可用逐漸放大的過程。舉例來說,我們使用鏈式設計模式構建的微服務,當其他的服務出現問題時,就會出現連鎖支應,導致整個服務鏈條不可用。

造成服務不可用的原因包括:

硬件故障;

網絡連接緩慢;

程序Bug;

緩存擊穿,一般發生在緩存應用重啓,所有緩存被清空時,以及短時間內大量緩存失效時。大量的緩存不命中,使請求直擊後端,造成服務提供者超負荷運行,引起服務不可用;

用戶大量請求。

那麼出現雪崩應該如何應對呢?

應對雪崩一般有以下幾種辦法。

流量控制

一般是使用Nginx進行流量控制,對流量大的應用採用分流和限制,這個功能也可以使用網關來完成。

服務自動擴容

取決於硬件的限制,也可以使用第三方的雲服務以達到擴容的效果。如果微服務構建得比較成熟,則可以通過容器的動態擴容來完成服務的擴容。

降級和資源隔離

資源隔離主要是對調用服務的線程池進行隔離,監控一般要細緻到線程級別,當發現某個線程佔用資源過高時,進行有效的處理來解決性能瓶頸。

我們根據具體業務將依賴服務分爲強依賴和弱依賴。強依賴服務不可用會導致當前業務中止,而弱依賴服務的不可用不會導致當前業務的中止。

不可用服務的調用快速失敗一般通過超時機制、熔斷器和熔斷後的降級方法來實現。

降級

在網絡訪問中,爲了優化用戶體驗,遇到超時的情況,可以直接放棄本次請求,不等待結果的返回,直接返回用戶默認數據,也可以降級爲從另一個服務或者使用緩存中設置的默認數據。

熔斷

熔斷是指錯誤達到某個設定的閾值,或者請求量超過閾值後,系統自動(或手動)阻止代碼或服務的執行調用,從而達到系統整體保護的效果。當檢測到系統可用時,需要恢復訪問。

熔斷器模式

熔斷器模式定義了熔斷器開關相互轉換的邏輯。

正常運行 (Closed)

當一個系統運行平穩時,成功狀態計數器用於測量彈性系統的穩定性,而故障表用於跟蹤任何故障。該設計確保當達到故障的閬值時,斷路器斷開電路,以防止進一步的資源請求。

失敗狀態 (Open)

在這個時刻,每-一個依賴調用是短路的,並拋出HystrixRuntimeException 異常,伴隨SHORTCIRCUIT失敗類型,給出異常明確的原因。一旦等待時間過後,Hystrix 斷路器移到半開放狀態。

半開放狀態

在這種狀態下,由Hystrix負責發送第一一個請求, 檢查系統的可用性,讓其他的請求快速失敗,直到得到依賴的響應。如果調用是成功的,則斷路器被重置爲Closed狀態;如果發生故障,則系統返回Open狀態,並且整個過程繼續循環。

斷路器是Hystrix庫默認提供的一個功能。斷路器的功能可以概括如下:

熔斷器對所有調用狀態進行驗證;

如果是closed狀態,則允許請求通過;

如果是open狀態,則失敗所有的請求;

如果是half-open狀態,則允許一個請求通過,並在成功或者失敗時,轉換成closed或open狀態。

Hystrix

Hystrix:通過服務熔斷、降級、限流、異步RPC等手段控制依賴服務的延遲與失敗。通過命令模式封裝調用來實現彈性保護,繼承HytrixCommand並且實現run方法,就完成了最簡單的封裝。可以爲分佈式服務提供彈性保護。

Hystrix的設計原則包括:資源隔離、熔斷器、命令模式。

斷路器機制

斷路器很好理解,當Hystrix Command請求後端服務失敗數量超過一定 比例,默認爲50%,斷路器會切換到開路狀態(open), 這時所有請求會直接失敗而不會發送到後端服務。斷路器保持在開路狀態一段時間後, 默認爲5秒,自動切換到半開路狀態(half-open), 這時會判斷下一次請求的返回情況。如果請求成功,則斷路器切回閉路狀態(closed),否則重新切換到開路狀態(open)。Hystrix 的斷路器就像我們家庭電路中的保險絲,一旦後端服務不可用,斷路器會直接切斷請求鏈,避免發送大量無效請求影響系統吞吐量,並且斷路器有自我檢測並恢復的能力。

fallback

fallback相當於降級操作。對於查詢操作,我們可以實現一個fallback 方法,當請求後端服務出現異常時,可以使用fallbak方法返回的值。fllback 方法的返回值一般是設置的默認值或者來自緩存。

資源隔離

在Hystrix中,主要通過線程池來實現資源隔離。通常在使用時我們會根據調用的遠程服務劃分出多個線程池。例如,調用產品服務的Command放入A線程池,調用賬戶服務的Command放入B線程池。這樣做的主要優點是運行環境被隔離開了,就算調用服務的代碼存在Bug或者由於其他原因導致自己所在線程池被耗盡時,不會對系統的其他服務造成影響。但代價就是維護多個線程池會對系統帶來額外的性能開銷。如果對性能有嚴格要求而且確信自己調用服務的客戶端代碼不會出問題,則可以使用Hystrix 的信號模式(Semaphores)來隔離資源。

Hystrix服務調用的內部邏輯如下圖所示

構建的Command對象,調用執行方法。

Hystrix檢查當前服務的熔斷器開關是否開啓,若開啓,則執行降級服務getFallback 方法。

若熔斷器開關關閉,則Hystrix檢查當前服務的線程池是否能接收新的請求,若超過線程池已滿,則執行降級服務getFallback 方法。

若線程池接收請求,則Hystrix開始執行服務調用具體邏輯run方法。

若服務執行失敗,則執行降級服務getFallback 方法,並將執行結果上報Metrics更新服務健康狀況。

若服務執行超時,則執行降級服務getFallback方法,並將執行結果上報Metrics更新服務健康狀況。

若服務執行成功,則返回正常結果。

若服務降級方法getFallback執行成功,則返回降級結果。

若服務降級方法getFallback執行失敗,則拋出異常。

以上就是小編整理的微服務Spring Cloud框架解析,只是小編的個人見解,有哪裏不準確的地方,還請大佬們多多指出,咱們共同學習進步~~~

喜歡文章或小編的朋友,請多多點贊評論轉發,你們的支持就是小編最大的動力!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章