一、若是通過斷路器的流量超過了必定的閾值,HystrixCommandProperties.circuitBreakerRequestVolumeThreshold()後端
舉個例子,好比要求在10s內,通過斷路器的流量必須達到20個(須要設置),這個時候Hystrix會開啓斷路器;若是在10s內,通過斷路器的流量才10個,那麼根本不會去判斷要不要斷路。ide
二、若是斷路器統計到的異常調用的佔比超過了必定的閾值,HystrixCommandProperties.circuitBreakerErrorThresholdPercentage()ui
若是達到了上面的要求,好比說在10s(時間窗口)內,通過斷路器的流量(只要執行一個command,這個請求就必定會通過斷路器)達到了30個;或者在10秒(時間窗口)內異常的訪問數量,佔到了必定的比例(須要設置),好比60%的請求都是異常(報錯,timeout,reject(好比信號量或線程池已滿)),這時候會開啓斷路。this
三、這時候斷路器從close狀態轉換到open狀態spa
四、斷路器打開的時候,全部通過該斷路器的請求所有被斷路,不調用後端服務,直接走fallback降級線程
五、通過了一段時間以後,HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds(),斷路器會進入半開狀態(half-open),讓一條請求通過斷路器,看能不能正常調用。若是調用成功了,那麼就自動恢復,轉到close狀態;斷路器,會自動恢復的。code
六、circuit breaker短路器的配置blog
(1)circuitBreaker.enabled接口
控制短路器是否容許工做,包括跟蹤依賴服務調用的健康情況,以及對異常狀況過多時是否容許觸發短路,默認是trueci
HystrixCommandProperties.Setter().withCircuitBreakerEnabled(boolean value)//控制是否開啓斷路器
(2)circuitBreaker.requestVolumeThreshold
設置一個rolling window,滑動窗口中,最少要有多少個請求時,才觸發開啓短路
舉例來講,若是設置爲20(默認值),那麼在一個10秒的滑動窗口內,若是隻有19個請求,即便這19個請求都是異常的,也是不會觸發開啓斷路器的。
HystrixCommandProperties.Setter().withCircuitBreakerRequestVolumeThreshold(int value)
(3)circuitBreaker.sleepWindowInMilliseconds
設置斷路器以後,須要在多長時間內直接reject請求(走降級),而後在這段時間以後,再從新進入到holf-open狀態,嘗試容許請求經過以及自動恢復,默認值是5000毫秒
HystrixCommandProperties.Setter().withCircuitBreakerSleepWindowInMilliseconds(int value)
(4)circuitBreaker.errorThresholdPercentage
設置異常請求量的百分比,當異常請求達到這個百分比時,就觸發打開斷路器,默認是50,也就是50%
HystrixCommandProperties.Setter().withCircuitBreakerErrorThresholdPercentage(int value)
(5)circuitBreaker.forceOpen
若是設置爲true的話,直接強迫打開斷路器,至關因而手動短路了,手動降級,默認false
HystrixCommandProperties.Setter().withCircuitBreakerForceOpen(boolean value)
(6)circuitBreaker.forceClosed
若是設置爲true的話,直接強迫關閉斷路器,至關因而手動中止短路了,手動升級,默認false
HystrixCommandProperties.Setter().withCircuitBreakerForceClosed(boolean value)
代碼:
/** * 獲取商品信息 * @author 張三丰 * */ public class GetProductInfoCommand extends HystrixCommand<ProductInfo> { private Long productId; public GetProductInfoCommand(Long productId) { super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ProductInfoService")) .andCommandKey(HystrixCommandKey.Factory.asKey("GetProductInfoCommand")) .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("GetProductInfoPool")) .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter() .withCoreSize(15) .withQueueSizeRejectionThreshold(10)) .andCommandPropertiesDefaults(HystrixCommandProperties.Setter() .withCircuitBreakerRequestVolumeThreshold(30)//10秒內有30個請求時,觸發斷路器 .withCircuitBreakerErrorThresholdPercentage(40)//當異常達到百分之40時,觸發斷路器 .withCircuitBreakerSleepWindowInMilliseconds(3000))//在3秒內直接refect請求走降級,3秒事後進入半開狀態 ); this.productId = productId; } @Override protected ProductInfo run() throws Exception { System.out.println("調用接口,查詢商品數據,productId=" + productId); if(productId.equals(-1L)) { throw new Exception(); } return JSONObject.parseObject("數據", ProductInfo.class); } @Override protected ProductInfo getFallback() { ProductInfo productInfo = new ProductInfo(); productInfo.setName("降級商品"); return productInfo; } }
斷路實驗:
public class CircuitBreakerTest { public static void main(String[] args) throws Exception { for(int i = 0; i < 15; i++) { String response = HttpClientUtils.sendGetRequest("http://localhost:8081/getProductInfo?productId=1"); System.out.println("第" + (i + 1) + "次請求,結果爲:" + response); } for(int i = 0; i < 25; i++) { String response = HttpClientUtils.sendGetRequest("http://localhost:8081/getProductInfo?productId=-1"); System.out.println("第" + (i + 1) + "次請求,結果爲:" + response); } Thread.sleep(5000); // 等待了5s後,時間窗口統計了,發現異常比例超過百分之40,就斷路了 for(int i = 0; i < 10; i++) { String response = HttpClientUtils.sendGetRequest("http://localhost:8081/getProductInfo?productId=-1"); System.out.println("第" + (i + 1) + "次請求,結果爲:" + response); } // Hystrix的統計單位是時間窗口,咱們必需要等到那個時間窗口過了之後,hystrix纔會看一下最近的這個時間窗口的異常狀況 // 好比說,最近的10秒內,有多少條數據,其中異常的數據有沒有到必定的比例 // 若是到了必定的比例,那麼纔會去短路 System.out.println("嘗試等待3秒鐘。。。。。。進入半開狀態"); Thread.sleep(3000); for(int i = 0; i < 10; i++) { String response = HttpClientUtils.sendGetRequest("http://localhost:8081/getProductInfo?productId=1"); System.out.println("第" + (i + 1) + "次請求,結果爲:" + response); } }