Hystrix 具備服務降級、服務容錯、服務熔斷、線程和信号隔離、請求緩存、請求合并以及服務監控等強大功能。
多層服務調用中,較低級别的服務中的服務故障可能導緻使用者級聯故障。當對特定服務的呼叫達到一定門檻值時(Hystrix中的預設值為5秒内的20次故障),電路打開,不進行通話。在錯誤和開路的情況下,開發人員可以提供後備。
下圖來自官方網站
Hystrix特性
1.請求熔斷: 當Hystrix Command請求後端服務失敗數量超過一定比例(預設50%), 斷路器會切換到開路狀态(Open). 這時所有請求會直接失敗而不會發送到後端服務. 斷路器保持在開路狀态一段時間後(預設5秒), 自動切換到半開路狀态(HALF-OPEN).這時會判斷下一次請求的傳回情況, 如果請求成功, 斷路器切回閉路狀态(CLOSED), 否則重新切換到開路狀态(OPEN).
2.服務降級:Fallback相當于是降級操作. 對于查詢操作, 我們可以實作一個fallback方法, 當請求後端服務出現異常的時候, 可以使用fallback方法傳回的值. fallback方法的傳回值一般是設定的預設值或者來自緩存.告知後面的請求服務不可用了,不要再來了。
3.依賴隔離(采用艙壁模式,Docker就是艙壁模式的一種):在Hystrix中, 主要通過線程池來實作資源隔離. 通常在使用的時候我們會根據調用的遠端服務劃分出多個線程池.比如說,一個服務調用兩外兩個服務,你如果調用兩個服務都用一個線程池,那麼如果一個服務卡在哪裡,資源沒被釋放。後面的請求又來了,導緻後面的請求都卡在哪裡等待,導緻你依賴的A服務把你卡在哪裡,耗盡了資源,也導緻了你另外一個B服務也不可用了。這時如果依賴隔離,某一個服務調用A B兩個服務,如果這時我有100個線程可用,我給A服務配置設定50個,給B服務配置設定50個,這樣就算A服務挂了,我的B服務依然可以用。
4.請求緩存:比如一個請求過來請求使用者的資料,你後面的請求也過來請求同一個使用者的資料,這時我不會繼續走原來的那條請求鍊路了,而是把第一次請求緩存過了,把第一次的請求結果傳回給後面的請求。
5.請求合并:我依賴于某一個服務,我要調用N次,比如說查資料庫的時候,我發了N條請求發了N條SQL然後拿到一堆結果,這時候我們可以把多個請求合并成一個請求,發送一個查詢多條資料的SQL的請求,這樣我們隻需查詢一次資料庫,提升了效率。
我們前面EurekaDiscovery2執行個體中,使用了Feign來調用EurekaDiscovery中的接口,Feign内部已包含了hystrix。下面我們先使用Feign來實作降級融斷。
在EurekaDiscovery2配置中添加
feign:
hystrix:
enabled: true # 開啟hystrix
我們添加一個Fallback類并實作HelloRemote接口
@Component
public class HelloFallback implements HelloRemote {
@Override
public String home(@RequestParam("name") String name) {
return name+"現在太擁擠了, 請稍後重試~-Feign";
}
}
我們指定fallback類為HelloFallback
@FeignClient(name= "eurekadiscovery", fallback = HelloFallback.class)
public interface HelloRemote {
@GetMapping("/hi")
public String home(@RequestParam("name") String name);
}
下面我們啟動執行個體來驗證一下
正常調用:
我們模拟EurekaDiscovery挂掉(關閉),觸發了服務降級
逾時導緻服務降級,預設feign調用逾時是1000毫秒,我們EurekaDiscovery中将線程sleep1000豪秒,同樣出現了上面一樣的服務降級。
我們可以通下面的配置來設定逾時時間
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
通過調整hystrix的逾時時間,服務能正常調用
當我們沒有使用Feign時也可直接引用Hystrix元件來實作在,我們在項目中引入spring-cloud-starter-netflix-hystrix
啟動類中我們添加注解@EnableCircuitBreaker 允許斷路器
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class EurekaDiscovery2Application {
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(EurekaDiscovery2Application.class, args);
}
}
我們通過@HystrixCommand
@HystrixCommand(fallbackMethod = "fallback")
public String home(@RequestParam("name") String name)
{
return restTemplate.getForEntity("http://EUREKADISCOVERY/hi?name="+name,String.class).getBody();
}
public String fallback(String name) {
return name+",現在太擁擠了, 請稍後重試~";
}
我們啟動執行個體,能正常調用
我們模拟EurekaDiscovery挂掉(關閉),觸發了服務降級
我們還可以通過@DefaultProperties(defaultFallback = "defaultFallback"),來指定預設的FallBack函數,這樣就不需要每個 @HystrixCommand 注解都指定一個FallBack函數了
@RestController
@DefaultProperties(defaultFallback = "defaultFallback")
public class HelloController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/hi")
@HystrixCommand
// @HystrixCommand(fallbackMethod = "fallback")
public String home(@RequestParam("name") String name)
{
return restTemplate.getForEntity("http://EUREKADISCOVERY/hi?name="+name,String.class).getBody();
}
public String fallback(String name) {
return name+",現在太擁擠了, 請稍後重試~";
}
public String defaultFallback()
{
return "現在太擁擠了, 請稍後重試~";
}
這樣我們降級後就會調用預設的FallBack函數
我們還可以通過@HystrixCommand來設定逾時時間,我們一般都是采用在配置檔案中設定逾時間時間。
@HystrixCommand(commandProperties = {
// 設定逾時時間為3秒
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
home:
execution:
isolation:
thread:
timeoutInMilliseconds: 1000