前言:
本篇博客主要是向大家分享Hystrix服務熔斷的相關理論及案例分析。
服務熔斷:
類比保險絲達到最大服務訪問後,直接拒絕訪問,拉閘限電,然後調用服務降級的方法並返回友好提示,
斷路器:
一句話就是家裏的保險絲。
<font color=>熔斷是什麼:
- 熔斷機制
熔斷機制是應對雪崩效應的一種微服務鏈路保護機制,當扇出鏈路的某個微服務出錯不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的調用,快速返回錯誤的響應信息。
當檢測到該節點微服務調用響應正常後,恢復調用鏈路在Springcloud 框架裏,熔斷機制通過Hystrix實現,Hystrix會監控微服務調用的狀況,當失敗的調用到一定閾值,缺省是5秒內20次調用失敗,就會啓動熔斷機制,熔斷機制的註解是:@HystrixCommand
package com.zcw.springcloud.service;
import cn.hutool.core.util.IdUtil;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.concurrent.TimeUnit;
/**
* @ClassName : PaymentService
* @Description :
* @Author : Zhaocunwei
* @Date: 2020-05-19 15:48
*/
@Service
public class PaymentService {
public String paymentInfo_OK(Integer id){
return "線程池: "+ Thread.currentThread().getName()+" paymentInfo_OK,id:"+id+"\t"+"O(∩_∩)O哈哈~";
}
@HystrixCommand(fallbackMethod ="paymentInfo_TimeOutHandler" ,commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public String paymentInfo_TimeOut(Integer id){
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return " 線程池: "+Thread.currentThread().getName()+" paymentInfo_TimeOut,id:"+id+"\t"+"O(∩_∩)O哈哈~"+ "耗時3秒鐘";
}
public String paymentInfo_TimeOutHandler(Integer id ){
return "線程池:"+Thread.currentThread().getName()+"paymentInfo_TimeOutHandler,id: "+ id+"\t"+"┭┮﹏┭┮";
}
//============服務熔斷==============================
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
@HystrixProperty(name="circuitBreaker.enabled",value = "true"),//是否開啓斷路器
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value="10"),//請求次數
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "10000"),//時間窗口期
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "60"),//失敗率達到多少後跳閘
})
public String paymentCircuitBreaker(@PathVariable("id") Integer id){
if(id<0){
throw new RuntimeException("************* id 不能負數");
}
String serialNumber = IdUtil.simpleUUID();
return Thread.currentThread().getName()+"\t"+"調用成功,流水號:"+serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){
return "id 不能負數,請稍後再試,o(╥﹏╥)o id:" + id;
}
}
//=============服務熔斷=============
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id){
String result = paymentService.paymentCircuitBreaker(id);
log.info("****************************result:"+result);
return result;
}
- 測試
正確姿勢:
錯誤姿勢:
總結:
根據官網提供的圖片流程,我們可以總結如下:
熔斷打開:
請求不再進行調用當前服務,內部設置時鐘一般爲MTTR(平均故障處理時間),當打開時長達到所設時鐘則進入半熔斷狀態。
熔斷關閉:
熔斷關閉不會對服務進行熔斷。
熔斷半開:
部分請求根據規則調用當前服務,如果請求成功且符合規則則認爲當前服務恢復正常,關閉熔斷。
原理分析
- 官斷路器流程圖
官網步驟:
斷路器在什麼情況下開始起作用:
涉及到斷路器的三個重要參數:快照時間窗、請求總數閾值、錯誤百分比閾值。
1.快照時間窗: 斷路器確定是否打開需要統計一些請求和錯誤數據,而統計的時間範圍就是快照時間窗,默認爲最近的10秒。
- 請求總數閾值:在快照時間窗內,必須滿足請求總數閾值纔有資格熔斷,默認爲20,意味着在10秒內,如果該hystrix命令的調用次數不足20次,即使所有的請求都超時或其他原因失敗,斷路器都不會打開。
- 錯誤百分比閾值: 當請求總數在快照時間窗內超過了閾值,比如發生了30次調用,如果在這30次調用中,有15次發生了超時異常,也就是超過50%的錯誤百分比,在默認設定50%閾值情況下,這時候就會將斷路器打開。
斷路器開啓或者關閉的條件:
1.當滿足一定的閾值的時候(默認10秒內超過20個請求次數)
2.當失敗率達到一定的時候(默認10秒內超過50%的請求失敗)
3.到達以上閾值,斷路器將會開啓
4.當開啓的時候,所有請求都不會進行轉發
5.一段時間之後(默認是5秒),這個時候斷路器是半開狀態,會讓其中一個請求進行轉發。如果成功,斷路器會關閉,若失敗,繼續開啓,重複4和5
斷路器打開之後:
1.再有請求調用的時候,將不會調用主邏輯,而是直接調用降級fallback.通過斷路器,實現了自動地發現錯誤並將降級邏輯切換爲主邏輯,減少響應延遲的效果。
2.原來的主邏輯要如何恢復呢:對於這一個問題,hystrix也爲我們實現了自動恢復功能。當斷路器打開,對主邏輯進行熔斷之後,hystrix會啓動一個休眠時間窗,在這個時間窗內,降級邏輯是臨時的成爲主邏輯,當休眠時間窗到期,斷路器將進入半開狀態,釋放一次請求到原來的主邏輯上,如果此次請求正常返回,那麼斷路器將繼續閉合,主邏輯恢復,如果這次請求依然有問題,斷路器繼續進入打開狀態,休眠時間窗重新計時。
最全配置: