斷路器(curcuit breaker)模式
在分布式環境下,特別是微服務結構的分布式系統中, 一個軟件系統調用另外一個遠程系統是非常普遍的。這種遠程調用的被調用方可能是另外一個進程,或者是跨網路的另外一臺主機, 這種遠程的調用和進程的內部調用最大的區別是,遠程調用可能會失敗,或者掛起而沒有任何回應,直到超時。更壞的情況是, 如果有多個調用者對同一個掛起的服務進行調用,那么就很有可能的是一個服務的超時等待迅速蔓延到整個分布式系統,引起連鎖反應, 從而消耗掉整個分布式系統大量資源。最終可能導致系統癱瘓。
斷路器(circuit breaker)模式就是為了防止在分布式系統中出現這種瀑布似的連鎖反應導致的災難。
一旦某個電器出問題,為了防止災難,電路的保險絲就會熔斷。斷路器類似于電路的保險絲, 實現思路非常簡單,可以將需要保護的遠程服務嗲用封裝起來,在內部監聽失敗次數, 一旦失敗次數達到某閥值后,所有后續對該服務的調用,斷路器截獲后都直接返回錯誤到調用方,而不會繼續調用已經出問題的服務, 從而達到保護調用方的目的, 整個系統也就不會出現因為超時而產生的瀑布式連鎖反應。
1. 基本模式
上圖是斷路器(curcuit breaker)的結構,它有兩個基本狀態(close和open)和一個基本trip動作:
close狀態下, client向supplier發起的服務請求, 直接無阻礙通過斷路器, supplier的返回值接直接由斷路器交回給client.
open狀態下,client向supplier發起的服務請求后,斷路器不會將請求轉到supplier, 而是直接返回client, client和supplier之間的通路是斷的
trip: 在close狀態下,如果supplier持續超時報錯, 達到規定的閥值后,斷路器就發生trip, 之后斷路器狀態就會從close進入open.
2. 擴展模式
基本的斷路器模式下,保證了斷路器在open狀態時,保護supplier不會被調用, 但我們還需要額外的措施可以在supplier恢復服務后,可以重置斷路器。一種可行的辦法是斷路器定期探測supplier的服務是否恢復, 一但恢復, 就將狀態設置成close。斷路器進行重試時的狀態為半開(half-open)狀態。
3. 斷路器的使用場合:
一個supplier一般很穩定,如果一旦故障發生后, 檢查和恢復需要的時間比較長,通常無法短時間內快速修復的,那么這種服務比較適合采用斷路器模式。否則很可能導致ping-pong效應。
3. 斷路器不適合的場合:
為了防止一個應用程序試圖調用一個遠程服務或訪問共享資源,如果??該操作是極有可能失敗, 這種模式可能不適合。
對于處理中的應用程序訪問本地專用資源,例如在存儲器內數據結構。在這種環境下通常也不適合,使用斷路器只會增加系統開銷。
下面直接介紹spring cloud的斷路器如何使用。
springcloud netflix實現了斷路器庫的名字叫hystrix. 在微服務架構下,通常會有多個層次的服務調用.下面是微服架構下, 瀏覽器端通過api訪問后臺微服務的一個示意圖:
一個微服務的超時失敗可能導致瀑布式連鎖反映,下圖中,hystrix通過自主反饋實現的斷路器,防止了這種情況發生。
圖中的服務b因為某些原因失敗,變得不可用,所有對服務b的調用都會超時。當對b的調用失敗達到一個特定的閥值(5秒之內發生20次失敗是hystrix定義的缺省值), 鏈路就會被處于open狀態, 之后所有所有對服務b的調用都不會被執行, 取而代之的是由斷路器提供的一個表示鏈路open的fallback消息. hystrix提供了相應機制,可以讓開發者定義這個fallbak消息.
open的鏈路阻斷了瀑布式錯誤, 可以讓被淹沒或者錯誤的服務有時間進行修復。這個fallback可以是另外一個hystrix保護的調用, 靜態數據,或者合法的空值. fallbacks可以組成鏈式結構,所以,最底層調用其它業務服務的第一個fallback返回靜態數據.
下面,進入正題,在之前的兩hello world服務集群中加入斷路器, 防止其中一個hello world掛掉后, 導致系統發生連鎖超時失敗。
1. 在maven工程(前面章節中介紹的ribbon或者feign工程)的pom.xml中添加hystrix庫支持斷路器
1
2
3
4
|
<dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-hystrix</artifactid> </dependency> |
2.在ribbon應用中使用斷路器
1). 在spring boot啟動類上添加@enablecircuitbreaker注解
1
2
3
4
5
6
7
8
|
@springbootapplication @enablediscoveryclient @enablecircuitbreaker public class serviceribbonapplication { public static void main(string[] args) { springapplication.run(serviceribbonapplication. class , args); } |
2). 用@hystrixcommand注解標注訪問服務的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@service public class helloservice { @autowired resttemplate resttemplate; @hystrixcommand (fallbackmethod = "servicefailure" ) public string gethellocontent() { return resttemplate.getforobject( "http://service-helloworld/" ,string. class ); } public string servicefailure() { return "hello world service is not available !" ; } } |
@hystrixcommand注解定義了一個斷路器,它封裝了gethellocontant()方法, 當它訪問的service-helloworld失敗達到閥值后,將不會再調用service-helloworld, 取而代之的是返回由fallbackmethod定義的方法servicefailure()。@hystrixcommand注解定義的fallbackmethod方法,需要特別注意的有兩點:
第一, fallbackmethod的返回值和參數類型需要和被@hystrixcommand注解的方法完全一致。否則會在運行時拋出異常。比如本例中,servicefailure()的返回值和gethellocontant()方法的返回值都是string。
第二, 當底層服務失敗后,fallbackmethod替換的不是整個被@hystrixcommand注解的方法(本例中的gethellocontant), 替換的只是通過resttemplate去訪問的具體服務。可以從中的system輸出看到, 即使失敗,控制臺輸出里面依然會有“call service-helloworld”。
啟動eureka服務,只啟動兩個helloworld服務,然后中斷其中一個(模擬其中一個微服務掛起),訪問http://localhost:8901/然后刷新, 由于有負載均衡可以看到以下兩個頁面交替出現。可以看到第二個被掛起的服務,被定義在ribbon應該里面的錯誤處理方法替換了。
4. 在feign應用中使用斷路器
1). feign內部已經支持了斷路器,所以不需要想ribbon方式一樣,在spring boot啟動類上加額外注解
2). 用@feignclient注解添加fallback類, 該類必須實現@feignclient修飾的接口。
1
2
3
4
5
|
@feignclient (name = "service-helloworld" , fallback = helloworldservicefailure. class ) public interface helloworldservice { @requestmapping (value = "/" , method = requestmethod.get) public string sayhello(); } |
3). 創建helloworldservicefailure類, 必須實現被@feignclient修飾的helloworldservice接口。注意添加@component或者@service注解,在spring容器中生成一個bean
1
2
3
4
5
6
7
8
|
@component public class helloworldservicefailure implements helloworldservice { @override public string sayhello() { system.out.println( "hello world service is not available !" ); return "hello world service is not available !" ; } } |
4). spring cloud之前的brixton版本中,feign是缺省是自動激活了斷路器的,但最近的dalston版本已經將缺省配置修改為禁止。
原因參見: https://github.com/spring-cloud/spring-cloud-netflix/issues/1277, 這一點要注意。所以要在feign中使用斷路器, 必須在application.yml中添加如下配置:
1
2
3
|
feign: hystrix: enabled: true |
5). 啟動feign應用, 訪問http://localhost:8902/hello, 可以一看到和ribbon一樣的效果。
參考:http://projects.spring.io/spring-cloud/spring-cloud.html#_circuit_breaker_hystrix_clients
http://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign-hystrix
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://www.cnblogs.com/chry/p/7279856.html