HytrixCommand實踐總結

一. 使用HystrixCommand編碼方式


//構造setter  

HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(group); 

HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(group); 

HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(service);

HystrixCommandProperties.Setter commandPropertiesDefaults = HystrixCommandProperties.Setter()

     .withExecutionTimeoutInMilliseconds(100)

     .withCircuitBreakerForceOpen(true);

HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults = HystrixThreadPoolProperties.Setter()

.withCoreSize(10)

.withQueueSizeRejectionThreshold(10);

 


HytrixCommand.Setter setter = HytrixCommand.Setter.withGroupKey(groupKey)  

  .andCommandKey(commandKey)  

  .andThreadPoolKey(threadPoolKey);

  .andCommandPropertiesDefaults(commandPropertiesDefaults)

  .andThreadPoolPropertiesDefaults(threadPoolPropertiesDefaults);

  

//構造command  

HystrixCommand<String> command = new HystrixCommand<String>(setter) {  

  protected String run() throws Exception {  

  logger.info("#####################  in hystrix thread");  

  Thread.sleep(time);  

  if(isException)  

  throw  new RuntimeException("exception in run");  

  return service+ ":return";  

  }  

  @Override  

  protected String getFallback() {  

  logger.info("#####################  in request thread");  

  return service+":fallback";  

  }  

};  

  

  

1 HystrixCommandKey

Hystrix使用單例模式存儲HystrixCommand,熔斷機制就是根據單實例上的調用情況統計實現的,所以每個HystrixCommand要有自己的名字,用於區分,同時用於依賴調用的隔離。HystrixCommandKey就是用於定義這個名字,如果沒有定義這個名字,Hystrix會使用其類名作爲其名字,可以使用HystrixCommandKey.Factory.asKey(String name)方法定義一個名稱。


2 HystrixThreadPoolKey

HystrixThreadPoolKey是HystrixCommand所在的線程池,如果該參數不設置則使用HystrixCommandGroupKey作爲HystrixThreadPoolKey,這種情況下同一個HystrixCommandGroupKey下的依賴調用共用同一個線程池內,如果不想共用同一個線程池,則需要設置該參數。可以使用HystrixThreadPoolKey.Factory.asKey(String name)方法設置。


3 HystrixCommandGroupKey

Hystrix需要對HystrixCommand進行分組,便於統計、管理,所以需要一個分組名稱,HystrixCommandGroupKey就是用於定義分組名稱,可以使用HystrixCommandGroupKey.Factory.asKey(String name)方法定義一個分組名。每個HystrixCommand必須要配置一個分組名,一個是用於分組,還有如果沒有配置HystrixThreadPoolKey,這個分組名將會用於線程池名。


4 HystrixThreadPoolProperties

從名稱上可以看出這是線程池的屬性配置,可以通過它設置核心線程數大小、最大線程數、任務隊列大小等,當然它也又一些默認的配置參數。


5 HystrixCommandProperties

這個就是HystrixCommand的屬性配置,它可以設置熔斷器是否可用、熔斷器熔斷的錯誤百分比、依賴調用超時時間等,它有一些默認的配置參數,如熔斷器熔斷的錯誤百分比默認值是50%、依賴調用超時時間默認值是1000毫秒。



二. 使用@HystrixCommand方式

這裏只講註解的使用方式以及比較重要的部分,如果需要了解全部查看:https://github.com/Netflix/Hystrix/wiki/How-To-Use

2.1 Hystrix command

2.1.1 同步執行

public class UserService {
...
    @HystrixCommand
    public User getUserById(String id) {
        return userResource.getUserById(id);
    }
}

2.1.2 異步執行

public class UserService {
...
    @HystrixCommand
    public Future<User> getUserByIdAsync(final String id) {
        return new AsyncResult<User>() {
            @Override
            public User invoke() {
                return userResource.getUserById(id);
            }
        };
    }
}

2.1.3 反應執行()

public class UserService {
    ...
    @HystrixCommand
    public Observable<User> getUserById(final String id) {
        return Observable.create(new Observable.OnSubscribe<User>() {
                @Override
                public void call(Subscriber<? super User> observer) {
                    try {
                        if (!observer.isUnsubscribed()) {
                            observer.onNext(userResource.getUserById(id));
                            observer.onCompleted();
                        }
                    catch (Exception e) {
                        observer.onError(e);
                    }
                }
            });
    }
}

2.1.4 三種模式使用區別

  • 同步執行:當執行到註解方法時,程序會順序執行。

  • 異步執行:當執行到註解方法時,會併發異步執行,返回一個Future對象,後面使用.get()方法來阻塞拿到結果。如果有多個方法時,執行時間就是其中最長的一個服務的執行時間。

  • 反應執行:當執行到註解方法時,返回一個觀察者。支持EAGER和LAZY模式。和同步異步執行的區別是,當對多個方法之間的返回結果不需要做合併而是希望當多個方法返回時觸發一些事件時比較適合使用該模式。

反應執行沒太明白,如果需要了解可以先參考下這個https://mcxiaoke.gitbooks.io/rxdocs/content/Intro.html

2.2 Fallback

@HystrixCommand(fallbackMethod = "fallback1")
User getUserById(String id) {
    throw new RuntimeException("getUserById command failed");
}
 
@HystrixCommand(fallbackMethod = "fallback2")
User fallback1(String id, Throwable e) {
    assert "getUserById command failed".equals(e.getMessage());
    throw new RuntimeException("fallback1 failed");
}
 
@HystrixCommand(fallbackMethod = "fallback3")
User fallback2(String id) {
    throw new RuntimeException("fallback2 failed");
}

注意點:

  • fallback應該和註解方法在同一類下

  • fallback的返回值和參數列表應該和註解方法一致,如果需要異常,則在末尾添加Throwable參數,對訪問修飾符無要求

  • fallback方法上可以繼續添加fallback

command和fallback只支持以下幾種組合:

  • sync command, sync fallback

  • async command, sync fallback

  • async command, async fallback

2.3 Error Propagation

@HystrixCommand(ignoreExceptions = {BadRequestException.class})
    public User getUserById(String id) {
        return userResource.getUserById(id);
    }

當遇到BadRequestException時不會進入fallback,而是直接拋出異常

2.4 Configuration

@HystrixCommand(groupKey="UserGroup", commandKey = "GetUserByIdCommand"
                commandProperties = {
                        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500")
                },
                threadPoolProperties = {
                        @HystrixProperty(name = "coreSize", value = "30"),
                        @HystrixProperty(name = "maxQueueSize", value = "101"),
                        @HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
                        @HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"),
                        @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"),
                        @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1440")
        })

參數

作用

備註

groupKey

表示所屬的group,一個group共用線程池

默認值:getClass().getSimpleName();

commandKey


默認值:當前執行方法名

execution.isolation.strategy

隔離策略,有THREAD和SEMAPHORE

默認使用THREAD模式,以下幾種可以使用SEMAPHORE模式:

  • 只想控制併發度

  • 外部的方法已經做了線程隔離

  • 調用的是本地方法或者可靠度非常高、耗時特別小的方法(如medis)

execution.isolation.thread.timeoutInMilliseconds

 

超時時間

默認值:1000

在THREAD模式下,達到超時時間,可以中斷

在SEMAPHORE模式下,會等待執行完成後,再去判斷是否超時

設置標準:

有retry,99meantime+avg meantime

沒有retry,99.5meantime

execution.timeout.enabled

是否打開超時

execution.isolation.thread.interruptOnTimeout

是否打開超時線程中斷THREAD模式有效

execution.isolation.semaphore.maxConcurrentRequests

信號量最大併發度SEMAPHORE模式有效,默認值:10

fallback.isolation.semaphore.maxConcurrentRequests

fallback最大併發度默認值:10

circuitBreaker.requestVolumeThreshold

熔斷觸發的最小個數/10s默認值:20

circuitBreaker.sleepWindowInMilliseconds

熔斷多少秒後去嘗試請求默認值:5000

circuitBreaker.errorThresholdPercentage

失敗率達到多少百分比後熔斷

默認值:50

主要根據依賴重要性進行調整

circuitBreaker.forceClosed

是否強制關閉熔斷如果是強依賴,應該設置爲true

coreSize

線程池coreSize

默認值:10

設置標準:qps*99meantime+breathing room

maxQueueSize

請求等待隊列

默認值:-1

如果使用正數,隊列將從SynchronizeQueue改爲LinkedBlockingQueue



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章