熔断hystrix

我们作为系统本身,既要关注上游系统的流量,也要关注下游系统或者中间件的响应。换而言之,就是注意自上而下一次请求的整体响应时间和请求量。作为中间系统,我们需要在上图中所有实线连接之处做防范。防止下游系统响应延迟或者是上游流量增加引起的导致的系统雪崩。

Hystrix简介

1:Hystrix使用命令模式HystrixCommand(Command)包装依赖调用逻辑,每个命令在单独线程中/信号授权下执行。

2:可配置依赖调用超时时间,超时时间一般设为比99.5%平均时间略高即可.当调用超时时,直接返回或执行fallback逻辑。

3:为每个依赖提供一个小的线程池(或信号),如果线程池已满调用将被立即拒绝,默认不采用排队.加速失败判定时间。

4:依赖调用结果分:成功,失败(抛出异常),超时,线程拒绝,短路。 请求失败(异常,拒绝,超时,短路)时执行fallback(降级)逻辑。

5:提供熔断器组件,可以自动运行或手动调用,停止当前依赖一段时间(10秒),熔断器默认错误率阈值为50%,超过将自动运行。

6:提供近实时依赖的统计和监控

调用链的使用
2.1.接口规划
2.1.1. 线程规划
原则上我们保证API所有请求最大线程并发数在10000 左右,根据接口相应的时间我们对长时间接口按照100个线程实现划分
这里补充下最大线程的概念:
在现有的框架里,我们使用的内嵌的tomcat容器,通过application.properties里的server.tomcat.max-threads来控制最大线程数。默认值为0;而如果要设置最大请求线程数,则需要获取tomcat的协议对象,对其对应属性来设置,默认是10000。我们为什么要控制在100呢?每个请求线程占用一定的JVM内存,为了保证JVM不会OOM。如果JVM堆栈较大或者每个请求较小,可以调高超时的线程数大小
一期
一期中,我们需要添加熔断的接口符合以下之一:
1)每次统计出的top10
2)普查接口调用在3S以上的所有API接口
2.2. 使用说明
2.2.1. API增加注解

/* groupKey :
 * commandKey:
 * threadPoolKey:三者值为一样,都为类名.方法名 如下:BizController.test
 * execution.isolation.thread.timeoutInMilliseconds : 接口的最大超时时常(毫秒),此参数每个API不同,建议设置为TP99的时间,即100次调用,按照每次调用耗时正排序,第99个耗时
 * 一般情况设置为此接口正常调用的最大超时时间
 * circuitBreaker.requestVolumeThreshold:失败率达到多少个启动计算熔断 固定3;只有在一个统计窗口内处理的请求数量达到这个阈值,才会进行熔断与否的判断
 * circuitBreaker.errorThresholdPercentage:失败率达到多少实现熔断,默认是成功率低于70开启熔断
 * circuitBreaker.errorThresholdPercentage:失败率达到多少启动熔断 固定30
 * coreSize:核心线程池大小,为此接口分配的线程,一般情况根据并发度来设置,QPS*TIMOUT*1.2
 * maxQueueSize : 等待队列大小 ,固定长度 50 ,
 * 异常封装即fallbackMethod将来做到eap-common里,返回特定result,
 * fallbackMethod (非必须,建议):失败错误,降级错误方法名字
 * fallbackMethod 定义方法签名必须和使用注解方法保持完全一致:即入参,出参 ;方法名建议:注解方法名+FallBack ,修饰权限:public
 *
 * 使用:1)需要设置groupKey、commandKey、threadPoolKey 为类名.方法名
 *     2)execution.isolation.thread.timeoutInMilliseconds  根据接口设置为此接口正常调用的最大超时时间
 *     3)coreSize 并发度来设置,QPS*TIMOUT*1.2
 */
@HystrixCommand(groupKey = "BizController.test", commandKey = "BizController.test",threadPoolKey = "BizController.test",
        commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "50000"),
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = Constants.HYSTRIX_CK_ERROR_NUMBER),
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = Constants.HYSTRIX_CK_ERROR_TP)
        },  threadPoolProperties = {
        @HystrixProperty(name = "coreSize", value = "12"),
        @HystrixProperty(name = "maxQueueSize", value = Constants.HYSTRIX_MAX_QUEUE_SIZE)} ,fallbackMethod = "testFallBack")
@RequestMapping("/test")
public Result test(Integer a){
    throw new IllegalStateException("ss");
}
 
 
/**
 *定义方法签名必须和使用注解方法保持完全一致:即入参,出参 b奥驰完全一致;
 * 方法名建议:注解方法名+FallBack ,修饰权限:public
 */
public Result testFallBack(Integer a){
    Result result = new Result();
    result.setCode(ErrorCode.STATUS_FAIL);
    result.setMsg("接口调用异常,fallBack处理结果集");
    return result;
}

推荐阅读更多精彩内容