Hystrix 斷路器
前提
分散式系統面臨的問題:複雜分散式體式結構中的應用程式有數十個依賴關係,每個依賴關係在某些時候將不可避免的失敗。
服務雪崩
多個微服務之間呼叫的時候,假設微服務A呼叫微服務B和微服務C,微服務B和微服務C又呼叫其它的微服務,這就是所謂的“扇出”。如果扇出的鏈路上某個微服務的呼叫響應時間過長或者不可用,對微服務A的呼叫就會佔用越來越多的系統資源,進而引起系統崩潰,所謂的“雪崩效應”。
對於高流量的應用來說,單一的後端依賴可能會導致所有伺服器上的所有資源都在幾秒鐘內飽和。比失敗更糟糕的是,這些應用程式還可能導致服務之間的延遲增加,備份佇列,執行緒和其他系統資源緊張,導致整個系統發生更多的級聯故障。這些都表示需要對故障和延遲進行隔離和管理,以便單個依賴關係的失敗,不能取消整個應用程式或系統。
所以,當你發現一個模組下的某個例項失敗後,這時候這個模組依然還會接受流量,然後這個有問題的模組還呼叫了其他的模組,這樣就會發生級聯故障,或者叫雪崩。
Hystrix 簡介
Hystrix
是一個用於處理分散式系統的延遲和容錯的開源庫,在分散式系統裡,許多依賴不可避免的會呼叫失敗,比如超時、異常等,Hystrix 能夠保證在一個依賴出問題的情況下,不會導致整體服務失敗,避免級聯故障,以提高分散式系統的彈性。
“斷路器” 本身是一種開關裝置,當某個服務單元發生故障之後,通過斷路器的故障監控(類似熔斷保險絲),向呼叫方返回一個符合預期的、可處理的備選響應(FallBack),而不是長時間的等待或者丟擲呼叫方無法處理的異常
功能
服務降級
不讓客戶端等待並立刻返回一個友好提示:伺服器忙,請稍後再試。(fallback)
那些情況會出現降級:
- 程式執行異常
- 超時
- 服務熔斷觸發服務降級
- 執行緒池/訊號量打滿也會導致服務降級
服務熔斷
類比保險絲達到最大服務訪問後,直接拒接訪問,拉閘限電,然後呼叫服務降級的方法並返回友好提示。
就是保險絲:服務的降級 -> 進而熔斷 -> 恢復呼叫的鏈路
服務限流
秒殺高併發等操作,嚴禁一窩蜂的過來擁擠,大家排隊,一秒鐘處理N個,有序進行。
接近實時的監控
超時故障
故障產生原因
服務提供者同一層次的其它介面服務被困死,因為 tomcat 執行緒池裡面的工作執行緒已經被擠佔完畢。
呼叫者此時呼叫服務提供者,客戶端訪問響應緩慢。
結論:
正因為有上述故障或不佳表現,才有我們的降級/容錯/限流等技術誕生。
如何解決
- 超時導致伺服器變慢(轉圈):
- 超時不在等待;
- 出錯(宕機或程式執行出錯):
- 出錯要提示指定資訊,而不是將錯誤日誌直接返回;
服務降級
降級配置:@HystrixCommand
服務端解決
設定自身呼叫超時時間的峰值,峰值內可以正常執行,超過了需要有兜底的方法處理,作服務降級fallback。
業務方法
@HystrixCommand(fallbackMethod = "paymentInfo_TimeoutHandler",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String payment_timout(Integer id) {
int timeNumber = 5;
try {
TimeUnit.SECONDS.sleep(timeNumber);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "執行緒池: " + Thread.currentThread().getName() + "payment_timout,id" + id + "O(∩_∩)O哈哈~\t" + "超時:" + timeNumber;
}
public String paymentInfo_TimeoutHandler(Integer id) {
return "執行緒池: " + Thread.currentThread().getName() + "paymentInfo_TimeoutHandler,id" + id + "(灬ꈍ ꈍ灬)";
}
啟動類
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker // 啟用Hystrix的服務降級
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class, args);
}
}
配置檔案
需要開啟 hystrix
feign:
hystrix:
enabled: true
定義全域性的 fallback
定義全域性的fallback方法
// 下面是全域性fallback方法
public String payment_Global_FallbackMethod()
{
return "Global異常處理資訊,請稍後再試,/(ㄒoㄒ)/~~";
}
啟動並指定對應的配置類
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
通過 Feign 實現服務降級
Feign 介面類
fallback = PaymentFallbackService.class
通過 FeignClient 中的 fallback 類指定對應的呼叫類。
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT" ,fallback = PaymentFallbackService.class)
public interface PaymentHystrixService
{
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
Feign 實現類
@Component
public class PaymentFallbackService implements PaymentHystrixService
{
@Override
public String paymentInfo_OK(Integer id)
{
return "-----PaymentFallbackService fall back-paymentInfo_OK ,o(╥﹏╥)o";
}
@Override
public String paymentInfo_TimeOut(Integer id)
{
return "-----PaymentFallbackService fall back-paymentInfo_TimeOut ,o(╥﹏╥)o";
}
}
服務熔斷
熔斷機制是應對雪崩效應的一種微服務鏈路保護機制。當扇出鏈路的某個微服務出錯不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的呼叫,快速返回錯誤的響應資訊。
當檢測到該節點微服務呼叫響應正常後,恢復呼叫鏈路。
在Spring Cloud框架裡,熔斷機制通過Hystrix實現。Hystrix會監控微服務間呼叫的狀況,當失敗的呼叫到一定閾值,預設是5秒內20次呼叫失敗,就會啟動熔斷機制。熔斷機制的註解是@HystrixCommand。
實踐案例
//=====服務熔斷
@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ㄒ)/~~ id: " +id;
}
熔斷型別
- 熔斷開啟:
- 請求不再進行呼叫當前服務,內部設定時鐘一般為MTTR(平均故障處理時間),當開啟時長達到所設時鐘則進入半熔斷狀態
- 熔斷關閉:
- 熔斷關閉不會對服務進行熔斷
- 熔斷半開:
- 部分請求根據規則呼叫當前服務,如果請求成功且符合規則則認為當前服務恢復正常,關閉熔斷
重要引數
快照時間窗、請求總數閥值、錯誤百分比閥值
- 快照時間窗:斷路器確定是否開啟需要統計一些請求和錯誤資料,而統計的時間範圍就是快照時間窗,預設為最近的10秒。
- 請求總數閥值:在快照時間窗內,必須滿足請求總數閥值才有資格熔斷。預設為20,意味著在10秒內,如果該hystrix命令的呼叫次數不足20次,即使所有的請求都超時或其他原因失敗,斷路器都不會開啟。
- 錯誤百分比閥值:當請求總數在快照時間窗內超過了閥值,比如發生了30次呼叫,如果在這30次呼叫中,有15次發生了超時異常,也就是超過50%的錯誤百分比,在預設設定50%閥值情況下,這時候就會將斷路器開啟。
斷路器開啟或關閉的條件
- 當滿足一定的閥值的時候(預設10秒內超過20個請求次數);
- 當失敗率達到一定的時候(預設10秒內超過50%的請求失敗);
- 到達以上閥值,斷路器將會開啟;
- 當開啟的時候,所有請求都不會進行轉發;
- 一段時間之後(預設是5秒),這個時候斷路器是半開狀態,會讓其中一個請求進行轉發。
如果成功,斷路器會關閉,若失敗,繼續開啟。重複4和5;
再有請求呼叫的時候,將不會呼叫主邏輯,而是直接呼叫降級fallback。通過斷路器,實現了自動地發現錯誤並將降級邏輯切換為主邏輯,減少響應延遲的效果。
原來的主邏輯要如何恢復呢?對於這一問題,hystrix也為我們實現了自動恢復功能。當斷路器開啟,對主邏輯進行熔斷之後,hystrix會啟動一個休眠時間窗,在這個時間窗內,降級邏輯是臨時的成為主邏輯,當休眠時間窗到期,斷路器將進入半開狀態,釋放一次請求到原來的主邏輯上,如果此次請求正常返回,那麼斷路器將繼續閉合,主邏輯恢復,如果這次請求依然有問題,斷路器繼續進入開啟狀態,休眠時間窗重新計時。
Hystrix 呼叫監控
除了隔離依賴服務的呼叫以外,Hystrix還提供了準實時的呼叫監控(Hystrix Dashboard),Hystrix會持續地記錄所有通過Hystrix發起的請求的執行資訊,並以統計報表和圖形的形式展示給使用者,包括每秒執行多少請求多少成功,多少失敗等。Netflix通過hystrix-metrics-event-stream專案實現了對以上指標的監控。Spring Cloud也提供了Hystrix Dashboard的整合,對監控內容轉化成視覺化介面。
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardMain9001.class, args);
}
}