諾禾-Hystrix

Hystrix簡介
Hystrix主要完成了下面的功用:

包裹懇求:運用 HystrixCommand(或 HystrixObservableCommand) 包裹對依賴的調用邏輯。每個命令在獨立的線程中執行,運用了設計形式中的‘命令形式’
跳閘機制:當某微效勞的錯誤率超越一定閾值時,能夠自動跳閘,中止懇求該效勞一段時間
資源隔離:Hystrix 爲每個微效勞都維護了一個小型的線程池(或信號量)假如該線程池已滿,發往該依賴的懇求就會被立刻回絕
監控:Hystrix 能夠近乎實時的監控運轉指標和配置的變化,例如勝利、失敗、超時和被回絕的懇求等
回退機制:當懇求勝利、失敗、超時和被回絕或者斷路器翻開時,執行回退邏輯。回退邏輯可由開發人員自行提供
自我修復:斷路器翻開一段時間後,會進入‘半開’狀態,允許一個懇求訪問效勞提供方,假如勝利。則關閉斷路器
運用 Hystrix
引入依賴

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>

在啓動類上添加 @EnableHystrix
兩種狀況下的回退辦法
非 Feign 調用下的回退辦法
編寫回退辦法
/**

  • getUserByAge 辦法 Hystrix 回退辦法
  • @param age
  • @return
    */
    public User getUserByAgeFallBack(Integer age){
    User user = new User();
    user.setName(“默許用戶”);
    user.setAge(age);
    return user;
    }
    在客戶端的辦法上聲明
    @HystrixCommand(fallbackMethod = “getUserByAgeFallBack”)
    測試:將效勞提供方的代碼打斷點。調用效勞消費方,會發現返回了默許用戶

需求留意:

回退辦法的返回值類型需求和原來辦法返回值類型相同(否則會報 FallbackDefinitionException: Incompatible return types)
回退辦法的參數列表也要和原來辦法相同(否則會報 FallbackDefinitionException: fallback method wasn’t found: getUserByAgeFallBack([class java.lang.Integer]))
當我寫下第二句時,發現書中下一節引見說能夠經過在回退辦法中添加第二個參數:ThrowEable 來捕獲異常,剖析調用失敗的緣由,我就曉得我錯了。爲了防止繼續得到錯誤的結論,我決議讀一讀 Hystrix 處置回退辦法的源碼
加點料:Hystrix 對回退辦法的封裝的源碼如下:
com.netflix.hystrix.contrib.javanica.utils.MethodProvider
public FallbackMethod find(Class<?> enclosingType, Method commandMethod, boolean extended) {
// 首先判別該辦法的 HystrixCommand 註解上有沒有 defaultFallback / fallbackMethod 配置回退辦法稱號
if (this.canHandle(enclosingType, commandMethod)) {
// 調用 doFind 辦法
return this.doFind(enclosingType, commandMethod, extended);
} else {
// 沒有配置的化就接着下一個判別
return this.next != null ? this.next.find(enclosingType, commandMethod, extended) : FallbackMethod.ABSENT;
}
}
find 辦法在用戶所懇求的辦法的 HystrixCommand 註解上有用 defaultFallback / fallbackMethod 配置回退辦法稱號的時分,會調用 doFind 辦法來尋覓回退辦法。該辦法的參數有兩個,enclosingType 是用戶所懇求的辦法的類字節碼文件,commandMethod 是用戶所懇求的辦法

首先經過 this.getFallbackName 獲取回退辦法稱號,接着經過獲取 commandMethod 的參數類型們

接着分兩種狀況:

回調辦法繼承於 commandMethod 且最後一個參數類型是 Throwable,則去掉回退辦法參數列表中的 Throwable 類型停止匹配
回調辦法不繼承於 commandMethod ,則存在兩個可能的參數類型列表: fallbackParameterTypes 和 extendedFallbackParameterTypes 前者是 commandMethod 是參數列表,後者是前者 + Throwable。然後兩個都停止匹配。接着運用 Java8 Optional API,按次第選取前者匹配到的辦法 / 後者 / 空返回
private FallbackMethod doFind(Class<?> enclosingType, Method commandMethod, boolean extended) {
String name = this.getFallbackName(enclosingType, commandMethod);
Class<?>[] fallbackParameterTypes = null;
if (this.isDefault()) {
fallbackParameterTypes = new Class[0];
} else {
fallbackParameterTypes = commandMethod.getParameterTypes();
}
if (extended && fallbackParameterTypes[fallbackParameterTypes.length - 1] == Throwable.class) {
fallbackParameterTypes = (Class[])ArrayUtils.remove(fallbackParameterTypes, fallbackParameterTypes.length - 1);
}
Class<?>[] extendedFallbackParameterTypes = (Class[])Arrays.copyOf(fallbackParameterTypes, fallbackParameterTypes.length + 1);
extendedFallbackParameterTypes[fallbackParameterTypes.length] = Throwable.class;
Optional exFallbackMethod = MethodProvider.getMethod(enclosingType, name, extendedFallbackParameterTypes);
Optional fMethod = MethodProvider.getMethod(enclosingType, name, fallbackParameterTypes);
Method method = (Method)exFallbackMethod.or(fMethod).orNull();
if (method == null) {
throw new FallbackDefinitionException("fallback method wasn’t found: " + name + “(” + Arrays.toString(fallbackParameterTypes) + “)”);
} else {
return new FallbackMethod(method, exFallbackMethod.isPresent(), this.isDefault());
}
}
由源碼能夠得到結論:回退辦法要麼參數列表和原始辦法相同,要麼加且僅加一個類型爲 Throwable 的參數。其他的都不行

Feign 客戶端下的回退辦法
設置:feign.hystrix.enabled: true

Feign 客戶端接口上的 @FeignClient 添加 fallback 屬性,指向回退類

回退類完成客戶端接口

feign的配置

feign:
hystrix:
enabled: true # 翻開 feign 的 hystrix 支持
留意回退類加上 @Component 接口,防止由於 Spring 容器找不到該類而啓動報錯

// Feign 客戶端接口上的 @FeignClient 添加 fallback 屬性,指向回退類
@FeignClient(name = “SERVICE-PROVIDER”, fallback = UserServiceFeignClientFallBack.class)
public interface UserServiceFeignClient {
@GetMapping("/api/v1/user/{age}")
User getUser(@PathVariable(“age”) Integer age);
/**
* 用戶列表
* @return
*/
@GetMapping("/api/v1/users")
List getUsers();
}
// 回退類完成客戶端接口
@Component
public class UserServiceFeignClientFallBack implements UserServiceFeignClient {
@Override
public User getUser(Integer age) {
return null;
}
@Override
public List getUsers() {
return null;
}
}
當採用 Feign 客戶端來完成回退的時分,前面的捕捉異常辦法就不起作用了,那我們應該如何來處置異常呢?能夠運用 @FeignClient 的 fallbackFactory 屬性

@FeignClient(name = “SERVICE-PROVIDER”, fallbackFactory = UserServiceFallbackFactory.class)
@Component
@Slf4j
public class UserServiceFallbackFactory implements FallbackFactory {
@Override
public UserServiceFeignClient create(Throwable t) {
// 日誌最好寫在各個 fallback 辦法中,而不要直接卸載 create辦法中
// 否則援用啓動時就會打印該日誌
return new UserServiceFeignClient() {
@Override
public User getUser(Integer age) {
log.info(“調用User效勞提供者失敗”, t);
User user = new User();
user.setName(“默許用戶”);
user.setAge(age);
return user;
}
@Override
public List getUsers() {
return null;
}
};
}
}
留意: **fallback 和 fallbackFactory 屬性同時存在時,fallback 的優先級更高。因而開發中假如需求處置異常,只需配置 fallbackFactory 屬性即可 **

防止業務異常走進回退辦法
在某些場景下,當發作業務異常時,我們並不想觸發 fallback。例如業務中判別年齡 age 不能小於 1,否則拋出異常

if(age < 1){
throw new KeatsException(ExceptionEnum.NUM_LESS_THAN_MIN);
}
這時 Hystrix 會捕捉到異常然後執行 fallback 辦法,我們能夠經過下面兩個辦法來防止:

繼承 HystrixBadRequestException 該類繼承自 RunntimeException
在 @HystrixCommand 添加屬性 ignoreExceptions = {KeatsException.class}
爲 Feign 禁用 Hystrix
只需翻開 feign 的 hystrix 支持開關,feign 就會運用斷路器包裹 feign 客戶端的一切辦法,但很多場景並不需求這樣。該如何禁用呢?

爲指定客戶端禁用。需求借助 Feign 的自定義配置。首先添加一個自定義配置類,然後配置到 @FeignClient 的 configuration 屬性中
@Configuration
public class FeignDisableHystrixConfiguration {
@Bean
@Scope(“prototype”)
public Feign.Builder feignBuilder(){
return Feign.builder();
}
}
@FeignClient(name = “SERVICE-PROVIDER”, configuration = {FeignDisableHystrixConfiguration.class})
全局禁用: feign.hystrix.enabled: false

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