Hystrix是什么
在微服務架構中,我們是將一個單體應用拆分成多個服務單元,各個服務單元之間通過注冊中心彼此發現和消費對方提供的服務,每個服務單元都是單獨部署,在各自的服務進程中運行,服務之間通過遠程調用實現信息交互,那么當某個服務的響應太慢或者故障,又或者因為網絡波動或故障,則會造成調用者延遲或調用失敗,當大量請求到達,則會造成請求的堆積,導致調用者的線程掛起,從而引發調用者也無法響應,調用者也發生故障。
比如電商中的用戶下訂單,我們有兩個服務,一個下訂單服務,一個減庫存服務,當用戶下訂單時調用下訂單服務,然后下訂單服務又調用減庫存服務,如果減庫存服務響應延遲或者沒有響應,則會造成下訂單服務的線程掛起等待,如果大量的用戶請求下訂單,或導致大量的請求堆積,引起下訂單服務也不可用,如果還有另外一個服務依賴于訂單服務,比如用戶服務,它需要查詢用戶訂單,那么用戶服務查詢訂單也會引起大量的延遲和請求堆積,導致用戶服務也不可用。
所以在微服務架構中,很容易造成服務故障的蔓延,引發整個微服務系統癱瘓不可用。
為了解決此問題,微服務架構中引入了一種叫熔斷器的服務保護機制。
熔斷器也有叫斷路器,他們表示同一個意思,最早來源于微服務之父Martin Fowler的論文CircuitBreaker一文。“熔斷器”本身是一種開關裝置,用于在電路上保護線路過載,當線路中有電器發生短路時,能夠及時切斷故障電路,防止發生過載、發熱甚至起火等嚴重后果。
微服務架構中的熔斷器,就是當被調用方沒有響應,調用方直接返回一個錯誤響應即可,而不是長時間的等待,這樣避免調用時因為等待而線程一直得不到釋放,避免故障在分布式系統間蔓延;
Spring Cloud Hystrix實現了熔斷器、線程隔離等一系列服務保護功能。該功能也是基于Netflix的開源框架Hystrix實現的,該框架的目標在于通過控制那些訪問遠程系統、服務和第三方庫的節點,從而對延遲和故障提供更強大的容錯能力。Hystrix具備服務降級、服務熔斷、線程和信號隔離、請求緩存、請求合并以及服務監控等強大功能。
在SpringCloud中使用熔斷器Hystrix是非常簡單和方便的,只需要簡單兩步即可:
1、添加依賴
<!--Spring Cloud熔斷器起步依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
2、在入口類中使用@EnableCircuitBreaker注解開啟斷路器功能,也可以使用一個名為@SpringCloudApplication的注解代替主類上的三個注解;
3、在調用遠程服務的方法上添加注解:@HystrixCommand(fallbackMethod="error")
hystrix默認超時時間是1000毫秒,如果你后端的響應超過此時間,就會觸發斷路器;
修改hystrix的默認超時時間:
@HystrixCommand(fallbackMethod="error", commandProperties={
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="1500")}) //熔斷器,調用不通,回調error()方法
public String webHello () {
Hystrix的服務降級
有了服務的熔斷,隨之就會有服務的降級,所謂服務降級,就是當某個服務熔斷之后,服務端提供的服務將不再被調用,此時由客戶端自己準備一個本地的fallback回調,返回一個默認值來代表服務端的返回;
這種做法,雖然不能得到正確的返回結果,但至少保證了服務的可用,比直接拋出錯誤或服務不可用要好很多,當然這需要根據具體的業務場景來選擇;
我們在調用服務提供者時,我們自己也有可能會拋異常,默認情況下方法拋了異常會自動進行服務降級,交給服務降級中的方法去處理;
當我們自己發生異常后,只需要在服務降級方法中添加一個Throwable類型的參數就能夠獲取到拋出的異常的類型,如下:
public String error(Throwable throwable) {
System.out.println(throwable.getMessage());
return "error";
}
此時我們可以在控制臺看到異常的類型;
如果遠程服務有一個異常拋出后我們不希望進入到服務降級方法中去處理,而是直接將異常拋給用戶,那么我們可以在@HystrixCommand注解中添加忽略異常,如下:
@HystrixCommand(fallbackMethod="error", ignoreExceptions = Exception.class)
自定義Hystrix請求的服務異常熔斷處理
我們也可以自定義類繼承自HystrixCommand來實現自定義的Hystrix請求,在getFallback方法中調用getExecutionException方法來獲取服務拋出的異常;
com.netflix.hystrix.HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(""))
Hystrix儀表盤(Hystrix Dashboard),就像汽車的儀表盤實時顯示汽車的各項數據一樣,Hystrix儀表盤主要用來監控Hystrix的實時運行狀態,通過它我們可以看到Hystrix的各項指標信息,從而快速發現系統中存在的問題進而解決它。
要使用Hystrix儀表盤功能,我們首先需要有一個Hystrix Dashboard,這個功能我們可以在原來的消費者應用上添加,讓原來的消費者應用具備Hystrix儀表盤功能,但一般地,微服務架構思想是推崇服務的拆分,Hystrix Dashboard也是一個服務,所以通常會單獨創建一個新的工程專門用做Hystrix Dashboard服務;
第一步:創建一個普通的Spring Boot工程
比如創建一個名為springcloud-hystrix-dashboard的Spring Boot工程,建立好基本的結構和配置;
第二步:添加相關依賴
在創建好的Spring Boot項目的 pom.xml文件中添加相關依賴,如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.5.RELEASE</version>
</dependency>
第三步:入口類上添加注解
添加好依賴之后,在入口類上添加@EnableHystrixDashboard注解開啟儀表盤功能,如下:
@SpringBootApplication
@EnableHystrixDashboard
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
第四步:屬性配置
最后,我們可以根據個人習慣配置一下application.properties文件,如下:server.port=3721
至此,我們的Hystrix監控環境就搭建好了;
Hystrix儀表盤工程已經創建好了,現在我們需要有一個服務,讓這個服務提供一個路徑為/actuator/hystrix.stream接口,然后就可以使用Hystrix儀表盤來對該服務進行監控了;
我們改造消費者服務,讓其能提供/actuator/hystrix.stream接口,步驟如下:
1、消費者項目需要有hystrix的依賴:
<!--Spring Cloud熔斷器起步依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.5.RELEASE</version>
</dependency>
2、需要有一個spring boot的服務監控依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
3、配置文件需要配置spring boot監控端點的訪問權限:
management.endpoints.web.exposure.include=*
這個是用來暴露 endpoints 的,由于 endpoints 中會包含很多敏感信息,除了 health 和 info 兩個支持直接訪問外,其他的默認不能直接訪問,所以我們讓它都能訪問,或者指定:
management.endpoints.web.exposure.include=hystrix.stream
4、訪問入口 http://localhost:8081/actuator/hystrix.stream
注意:這里有一個細節需要注意,要訪問/hystrix.stream接口,首先得訪問consumer工程中的任意一個其他接口,否則直接訪問/hystrix.stream接口時會輸出出一連串的ping: ping: …,先訪問consumer中的任意一個其他接口,然后再訪問/hystrix.stream接口即可;