• Spring Boot中使用断路器


               断路器本身是电路上的一种过载保护装置,当线路中有电器发生短路时,它能够及时的切断故障电路以防止严重后果发生。通过服务熔断(也可以称为断路)、降级、限流(隔离)、异步RPC等手段控制依赖服务的延迟与失败,防止整个服务雪崩。一个断路器可以装饰并且检测了一个受保护的功能调用。根据当前的状态决定调用时被执行还是回退。通常情况下,一个断路器实现三种类型的状态:open、half-open以及closed:

    1. closed状态的调用被执行,事务度量被存储,这些度量是实现一个健康策略所必备的。
    2. 倘若系统健康状况变差,断路器就处在open状态。此种状态下,所有调用会被立即回退并且不会产生新的调用。open状态的目的是给服务器端回复和处理问题的时间。
    3. 一旦断路器进入一个open状态,超时计时器开始计时。如果计时器超时,断路器切换到half-open状态。在half-open状态调用间歇性执行以确定问题是否已解决。如果解决,状态切换回closed状态。

             断路器背后的基本思想非常简单。将受保护的函数调用包装在断路器对象中,该对象监视故障。一旦故障达到某个阈值,断路器就会跳闸,并且所有对断路器的进一步调用都会返回错误,而根本不会进行受保护的呼叫。通常,如果断路器跳闸,您还需要某种监控器警报。

     如何快速使用Hystrix呢?下面跟着我1234……

    1、加入@EnableCircuitBreaker注解

    @EnableCircuitBreaker
    @SpringBootApplication
    @EnableEurekaClient
    @EnableFeignClientspublic class DroolsAppApplication {
        public static void main(String[] args) {
            SpringApplication.run(DroolsAppApplication.class, args);
        }
    }

    Hystrix整体执行过程,首先,Command会调用run方法,如果run方法超时或者抛出异常,且启用了降级处理,则调用getFallback方法进行降级;

    2、使用@HystrixCommand注解

     @HystrixCommand(fallbackMethod = "reliable")
        public String readingList() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return "jinpingmei";
        }
    
        public String reliable() {
            return "you love interesting book";
        }

    3、添加引用

        compile("org.springframework.cloud:spring-cloud-starter-hystrix")
        compile('org.springframework.cloud:spring-cloud-starter-turbine')

    4、设置超时时间

    hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000

         执行结果如下:

        正常应该返回:

    你不要喜欢jinpingmei,要喜欢有意思的书;这样使用好舒服啊,@EnableCircuitBreaker这个注解就这么强大吗?

    HystrixCommandAspect 通过AOP拦截所有的@HystrixCommand注解的方法,从而使得@HystrixCommand能够集成到Spring boot中,

    HystrixCommandAspect的关键代码如下:

    1.方法 hystrixCommandAnnotationPointcut() 定义拦截注解HystrixCommand

     2.方法 hystrixCollapserAnnotationPointcut()定义拦截注解HystrixCollapser

     3.方法methodsAnnotatedWithHystrixCommand(…)通过@Around(…)拦截所有HystrixCommand和HystrixCollapser注解的方法。详细见方法注解

    @Aspect
    public class HystrixCommandAspect {

    private static final Map<HystrixPointcutType, MetaHolderFactory> META_HOLDER_FACTORY_MAP;

    static {
    META_HOLDER_FACTORY_MAP = ImmutableMap.<HystrixPointcutType, MetaHolderFactory>builder()
    .put(HystrixPointcutType.COMMAND, new CommandMetaHolderFactory())
    .put(HystrixPointcutType.COLLAPSER, new CollapserMetaHolderFactory())
    .build();
    }

    @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)")

    public void hystrixCommandAnnotationPointcut() {
    }

    @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)")
    public void hystrixCollapserAnnotationPointcut() {
    }

    @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()")
    public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
    Method method = getMethodFromTarget(joinPoint);
    Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint);
    if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {
    throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " +
    "annotations at the same time");
    }
    MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));
    MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
    HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
    ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
    metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();
    Object result;
    try {
    result = CommandExecutor.execute(invokable, executionType, metaHolder);
    } catch (HystrixBadRequestException e) {
    throw e.getCause();
    }
    return result;
    }

    那么HystrixCommandAspect是如何初始化,是通过HystrixCircuitBreakerConfiguration实现的

    @Configuration
    public class HystrixCircuitBreakerConfiguration {
    
    @Bean
    public HystrixCommandAspect hystrixCommandAspect() {
    return new HystrixCommandAspect();
    }

    那么谁来触发HystrixCircuitBreakerConfiguration执行初始化

    先看spring-cloud-netflix-core**.jar包的spring.factories里有这段配置,是由注解EnableCircuitBreaker触发

    org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=
    org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration


    那么@EnableCircuitBreaker如何触发HystrixCircuitBreakerConfiguration
    通过源码查看,此类通过@Import初始化EnableCircuitBreakerImportSelector类

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Import(EnableCircuitBreakerImportSelector.class)
    public @interface EnableCircuitBreaker {
    }

              EnableCircuitBreakerImportSelector是SpringFactoryImportSelector子类。此类在初始化后,会执行selectImports(AnnotationMetadata metadata)的方法。此方法会根据注解启动的注解(这里指@EnableCircuitBreaker)从spring.factories文件中获取其配置需要初始化@Configuration类(这里是org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration),从而最终初始化HystrixCommandAspect 类,从而实现拦截HystrixCommand的功能

              以上就是通过@EnableCircuitBreake可以开启Hystrix的原理。Hystrix用到了观察者模式AbstractCommand.executeCommandAndObserve()模式,下次我们来深入说一下观察者模式。欢迎拍砖!

  • 相关阅读:
    分析脚本搭建docker环境:python, R
    python 正则
    xargs的用法
    sed 用法
    linux系统时区问题
    docker, docker-compose安装和使用
    订单相关
    python开发接口文档
    mysql中的乐观锁,库存相关的简单实现
    mysql中的锁
  • 原文地址:https://www.cnblogs.com/viaiu/p/9534153.html
Copyright © 2020-2023  润新知