文章目錄
一、線程隔離示意圖:
解讀:
Hystrix爲每個依賴服務調用分配一個小的線程池,如果線程池已滿調用將被立即拒絕,默認不採用排隊.加速失敗判定時間。
用戶的請求將不再直接訪問服務,而是通過線程池中的空閒線程來訪問服務,如果線程池已滿,或者請求超時,則會進行降級處理,什麼是服務降級?
服務降級:優先保證核心服務,而非核心服務不可用或弱可用
用戶的請求故障時,不會被阻塞,更不會無休止的等待或者看到系統崩潰,至少可以看到一個執行結果(例如返回友好的提示信息) 。
服務降級雖然會導致請求失敗,但是不會導致阻塞,而且最多會影響這個依賴服務對應的線程池中的資源,對其它服務沒有響應。
觸發Hystix服務降級的情況:
- 線程池已滿
- 請求超時
二、實踐代碼
1、首先在itcast-service-consumer的pom.xml中引入Hystrix依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2、開啓熔斷
可以看到,我們類上的註解越來越多,在微服務中,經常會引入上面的三個註解,於是Spring就提供了一個組合註解:@SpringCloudApplication
因此,我們可以使用這個組合註解來代替之前的3個註解。
@SpringCloudApplication
public class ItcastServiceConsumerApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ItcastServiceConsumerApplication.class, args);
}
}
3、編寫降級邏輯
我們改造itcast-service-consumer,當目標服務的調用出現故障,我們希望快速失敗,給用戶一個友好提示。因此需要提前編寫好失敗時的降級處理邏輯,要使用HystixCommond來完成:
@Controller
@RequestMapping("consumer/user")
public class UserController {
@Autowired
private RestTemplate restTemplate;
@GetMapping
@ResponseBody
@HystrixCommand(fallbackMethod = "queryUserByIdFallBack")
public String queryUserById(@RequestParam("id") Long id) {
String user = this.restTemplate.getForObject("http://service-provider/user/" + id, String.class);
return user;
}
public String queryUserByIdFallBack(Long id){
return "請求繁忙,請稍後再試!";
}
}
要注意,因爲熔斷的降級邏輯方法必須跟正常邏輯方法保證:相同的參數列表和返回值聲明。失敗邏輯中返回User對象沒有太大意義,一般會返回友好提示。所以我們把queryById的方法改造爲返回String,反正也是Json數據。這樣失敗邏輯中返回一個錯誤說明,會比較方便。
說明:
- @HystrixCommand(fallbackMethod = “queryByIdFallBack”):用來聲明一個降級邏輯的方法
測試:
當itcast-service-provder正常提供服務時,訪問與以前一致。但是當我們將itcast-service-provider停機時,會發現頁面返回了降級處理信息:
4、默認FallBack
我們剛纔把fallback寫在了某個業務方法上,如果這樣的方法很多,那豈不是要寫很多。所以我們可以把Fallback配置加在類上,實現默認fallback:
@Controller
@RequestMapping("consumer/user")
@DefaultProperties(defaultFallback = "fallBackMethod") // 指定一個類的全局熔斷方法
public class UserController {
@Autowired
private RestTemplate restTemplate;
@GetMapping
@ResponseBody
@HystrixCommand // 標記該方法需要熔斷
public String queryUserById(@RequestParam("id") Long id) {
String user = this.restTemplate.getForObject("http://service-provider/user/" + id, String.class);
return user;
}
/**
* 熔斷方法
* 返回值要和被熔斷的方法的返回值一致
* 熔斷方法不需要參數
* @return
*/
public String fallBackMethod(){
return "請求繁忙,請稍後再試!";
}
}
- @DefaultProperties(defaultFallback = “defaultFallBack”):在類上指明統一的失敗降級方法
- @HystrixCommand:在方法上直接使用該註解,使用默認的剪輯方法。
- defaultFallback:默認降級方法,不用任何參數,以匹配更多方法,但是返回值一定一致
5、設置超時
在之前的案例中,請求在超過1秒後都會返回錯誤信息,這是因爲Hystix的默認超時時長爲1,我們可以通過配置修改這個值:
我們可以通過hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds來設置Hystrix超時時間。該配置沒有提示。
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000 # 設置hystrix的超時時間爲6000ms
改造服務提供者
改造服務提供者的UserController接口,隨機休眠一段時間,以觸發熔斷:
@GetMapping("{id}")
public User queryUserById(@PathVariable("id") Long id) {
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return this.userService.queryUserById(id);
}