六.Hystrix斷路器

斷路器工做原理

一、若是通過斷路器的流量超過了必定的閾值,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);  
        }
    }
    
相關文章
相關標籤/搜索