精华内容
下载资源
问答
  • Hystrix的简单实现

    2019-11-22 16:30:43
    这次要简单实现Hystrix功能,在上篇博客基础上改动几步就好了。 这里先简单说下自己Hystrix的理解: 它就和我们平时生活中断路器一样,每当线路中有电路发生短路时,为了防止危害,断路器就会开启来切断故障...

    项目结构可参考:上一篇博客

    这次要简单实现Hystrix功能,在上篇博客的基础上改动几步就好了。

    这里先简单说下自己对Hystrix的理解:

    它就和我们平时的生活中的断路器一样,每当线路中有电路发生短路时,为了防止危害,断路器就会开启来切断故障电路,它对电路起到了一种保护作用。同理,在微服务中,每个服务之间会相互调用,比如订单服务调用库存服务,如果在订单服务在调用库存服务时,库存服务发生故障,那么请求就会进入长时间的等待,长时间等待后,才会出现请求库存服务失败,进而创建订单失败结果。那么如果是在高并发的场景下,库存服务出现故障,会导致大量线程被占用而无法释放,越来越多的请求会被阻塞,最后会导致订单服务也不可用。如果服务的调用链路比较长的话,那么下游服务的故障就会渐渐的影响到上游的所有服务,导致服务雪崩。

    所以这时引入Hystrix(熔断器)来解决上述情况,当确定服务发生故障时,我们可以采用服务熔断和服务降级,设置降级的处理方式,这样上游服务在下游服务出现故障时,就不用长时间的等待下去,可以回调降级方法,及时给用户响应。更重要的是,它解决了可能出现的服务雪崩现象,维持了整个微服务的稳定性通知。当然Hystrix不止只有服务熔断,服务降级的功能,它还具备其他的类似请求缓存,请求合并等功能。

    • 服务熔断:这里要特别说下服务熔断,服务熔断有3种状态,分别是开启,关闭,半熔断,默认是关闭
    • 开启:在调用下游服务时,在规定的时间内,Hystrix默认是10秒,调用出错的比例达到一定得阈值,就会开启Hystrix,之后调用服务时都会调用降级方法。
    • 关闭:关闭就代表着服务是正常的,Hystrix不做任何限制。
    • 半熔断:为什么还会有这个状态,要知道,我们熔断器不可能是永久的,要是永久的话,那下游服务就没意义了,所以在开启Hystrix一段时间后,默认是5秒,Hystrix会进入
      半熔断的状态,它会尝试性的去调用被熔断的这个接口,如果成功率达标,那么就关闭Hystrix,正常调用服务,不再调用降级方法,反之则继续开启Hystrix。

    下面就是简单的Hystrix使用demo:

    首先导入Hystrix依赖:

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

    其次在spring boot启动类上增加注解@EnableCircuitBreaker开启熔断器:

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

    最后在调用的服务方法上增加@HystrixCommand(fallbackMethod = “fallback”),fallbackMethod里的值表示在该方法调用服务失败后,回滚调用的方法:

    @Service
    public class RibbonService {
        @Autowired
        private RestTemplate restTemplate;
    
        @HystrixCommand(fallbackMethod = "fallback")
        public String helloRibbon(String name) {
            return restTemplate.getForObject("http://eureka-client/helloWorld/" + name, String.class);
        }
    
        /**
         * 调用helloRibbon失败后的降级方法
         *
         * @param name
         * @return
         */
        public String fallback(String name) {
            return "error" + name;
        }
    }
    

    服务正常调用情况如图:
    在这里插入图片描述
    在这里插入图片描述

    断掉端口为8762的服务,效果如图:
    在这里插入图片描述
    在这里插入图片描述
    可以看到在8762端口的服务断掉后,我们调用时,页面并没有返回错误,而是给了我们降级方法的返回响应。这就说明Hystrix已经起到了作用。

    展开全文
  • 前言 随着业务的越来越复杂,保证程序的健壮性对程序猿来说也变得更加的重要,毕竟不写Bug的程序猿不是一个好的程序猿...②我们怎样去自己实现一个简单的熔断? 自定义熔断的实现 这里咱们简单的实现了一个超时后...

    前言

    随着业务的越来越复杂,保证程序的健壮性对程序猿来说也变得更加的重要,毕竟不写Bug的程序猿不是一个好的程序猿。但怎样尽可能的保证咱们的程序能够稳定的运行,以及出错后能够进行相应的补偿,这里就需要咱们使用熔断机制了。

    PS:在进入正文之前,不妨思考一下两个问题:
    ①熔断机制究竟为我们解决了什么问题?
    ②我们怎样去自己实现一个简单的熔断?


    自定义熔断的实现

    这里咱们简单的实现了一个超时后进行熔断的例子,这里有用到AspectJ的相关知识,对于熟悉Spring AOP知识的同学应该没什么问题。

    主要分为两步:

    1. 使用Future控制是否超时,超时后将任务cancel掉。
    2. 调用咱们自己定义好的fallback方法进行处理。在这里需要注意的是,fallback方法参数应该要与原方法相同,这样咱们才能进行补偿措施。例如:咱们可以在fallback方法借助消息中间件将这些参数进行存储,然后在适当的时候从消息中间件中读取出来进行补偿消费处理。
     1@RestController
    2public class HelloController {
    3    private Random random = new Random();
    4
    5    @MyHystrixCommand(fallback="errorMethod")
    6    @RequestMapping("/hello")
    7    public String hello(@RequestParam("name") String message) throws InterruptedException {
    8        int time = random.nextInt(200);
    9        System.out.println("spend time : " + time + "ms");
    10        Thread.sleep(time);
    11        System.out.println("hhhhhhhhhhhhhhhhhhhhhhhhh");
    12        return "hello world:" + message;
    13    }
    14
    15    public String errorMethod(String message) {
    16        return "error message";
    17    }
    18}
    复制代码
    1@Target(ElementType.METHOD)
    2@Retention(RetentionPolicy.RUNTIME)
    3@Documented
    4public @interface MyHystrixCommand {
    5    int value() default 100;
    6    String fallback() default "";
    7}
    复制代码
     1@Aspect
    2@Component
    3public class MyHystrixCommandAspect {
    4
    5    ExecutorService executor = Executors.newFixedThreadPool(10);
    6
    7    @Pointcut(value = "@annotation(MyHystrixCommand)")
    8    public void pointCut() {
    9
    10    }
    11
    12    @Around(value = "pointCut()&&@annotation(hystrixCommand)")
    13    public Object doPointCut(ProceedingJoinPoint joinPoint, MyHystrixCommand hystrixCommand) throws Throwable {
    14        int timeout = hystrixCommand.value();
    15        Future future = executor.submit(() -> {
    16            try {
    17                return joinPoint.proceed();
    18            } catch (Throwable throwable) {
    19            }
    20            return null;
    21        });
    22        Object returnValue = null;
    23        try {
    24            returnValue = future.get(timeout, TimeUnit.MILLISECONDS);
    25        } catch (InterruptedException | ExecutionException | TimeoutException e) {
    26            future.cancel(true);
    27            if (StringUtils.isBlank(hystrixCommand.fallback())){
    28                throw new Exception("fallback is null");
    29            }
    30            returnValue = invokeFallbackMethod(joinPoint, hystrixCommand.fallback());
    31        }
    32        return returnValue;
    33    }
    34
    35    private Object invokeFallbackMethod(ProceedingJoinPoint joinPoint, String fallback) throws Exception {
    36        Method method = findFallbackMethod(joinPoint, fallback);
    37        if (method == null) {
    38            throw new Exception("can not find fallback :" + fallback + " method");
    39        } else {
    40            method.setAccessible(true);
    41            try {
    42                Object invoke = method.invoke(joinPoint.getTarget(), joinPoint.getArgs());
    43                return invoke;
    44            } catch (IllegalAccessException | InvocationTargetException e) {
    45                throw e;
    46            }
    47        }
    48    }
    49
    50
    51    private Method findFallbackMethod(ProceedingJoinPoint joinPoint, String fallbackMethodName) {
    52        Signature signature = joinPoint.getSignature();
    53        MethodSignature methodSignature = (MethodSignature) signature;
    54        Method method = methodSignature.getMethod();
    55        Class<?>[] parameterTypes = method.getParameterTypes();
    56        Method fallbackMethod = null;
    57        try {
    58        //这里通过判断必须取和原方法一样参数的fallback方法
    59            fallbackMethod = joinPoint.getTarget().getClass().getMethod(fallbackMethodName, parameterTypes);
    60        } catch (NoSuchMethodException e) {
    61        }
    62        return fallbackMethod;
    63    }
    64
    65}
    复制代码

    当然,上述例子只是一个简单的超时后熔断处理的实现方式。咱们在实际应用中,还有可能并发超过指定阈值后咱们也需要进行降级处理,一个最普通的场景:秒杀案例。这些东西在Hystrix中都有相应的处理,它提供了线程池和信号量这两种方式去解决并发的问题。


    什么是Hystrix?

    咱们看一下官方介绍

    In a distributed environment, inevitably some of the many service dependencies will fail. Hystrix is a library that helps you control the interactions between these distributed services by adding latency tolerance and fault tolerance logic. Hystrix does this by isolating points of access between the services, stopping cascading failures across them, and providing fallback options, all of which improve your system’s overall resiliency.

    在分布式环境中,调用一些服务不可避免的会出现失败,Hystrix帮助咱们添加了一些容忍策略,并且将服务进行隔离处理,防止一个服务的失败影响到了另一个服务的调用,这些都提高了咱们系统的弹性。


    Hystrix的处理流程

    这里咱们结合一下Spring Cloud Hystrix进行说明,从HystrixCommandAspect开始分析:

     1@Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()")
    2    public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
    3        Method method = getMethodFromTarget(joinPoint);
    4        ...
    5        MetaHolder metaHolder = metaHolderFactory.create(joinPoint);//第一步
    6        HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);//第二步
    7        ...
    8        Object result;
    9        try {
    10            //第三步
    11            if (!metaHolder.isObservable()) {
    12                result = CommandExecutor.execute(invokable, executionType, metaHolder);
    13            } else {
    14                result = executeObservable(invokable, executionType, metaHolder);
    15            }
    16        } 
    17        ....
    18        return result;
    19    }
    复制代码

    这个切面主要针对HystrixCommandHystrixCollapser这两个注解,前者用于进行熔断降级处理,后者用来根据配置进行合并请求(类比数据库操作,将多个insert语句合并成一个insert batch语句)。咱们侧重进行HystrixCommand这一块的分析。

    第一步:获取元数据(MetaHolder)

    这段代码对应上面的MetaHolder metaHolder = metaHolderFactory.create(joinPoint);,里面封装了比如调用方法method,参数args,方法所属对象target,动态代理对象proxy,回调方法fallbackMethod等等一些元数据的封装。这些数据在创建命令对象时会被使用。

    第二步:获取调用者(HystrixInvokable)

    它持有一个命令对象,并且可以在合适的时候通过这个命令对象完成具体的业务逻辑,针对HystrixCommand上述的命令对象就是GenericObservableCommandGenericCommand的一种,这里命令对象的选择和方法的返回值有关,如果返回值为Observable类型,则创建GenericObservableCommand命令,否则创建GenericCommand命令。

    第三步:执行命令(execute)
     1    public static Object execute(HystrixInvokable invokable, ExecutionType executionType, MetaHolder metaHolder) throws RuntimeException {
    2        ...
    3        switch (executionType) {
    4            case SYNCHRONOUS: {
    5                return castToExecutable(invokable, executionType).execute();
    6            }
    7            case ASYNCHRONOUS: {
    8                HystrixExecutable executable = castToExecutable(invokable, executionType);
    9                if (metaHolder.hasFallbackMethodCommand()
    10                        && ExecutionType.ASYNCHRONOUS == metaHolder.getFallbackExecutionType()) {
    11                    return new FutureDecorator(executable.queue());
    12                }
    13                return executable.queue();
    14            }
    15            case OBSERVABLE: {
    16                HystrixObservable observable = castToObservable(invokable);
    17                return ObservableExecutionMode.EAGER == metaHolder.getObservableExecutionMode() ? observable.observe() : observable.toObservable();
    18            }
    19            ...
    20        }
    21    }
    复制代码

    从上面的代码段中,可以很容易的看出共有三种策略,同步、异步、OBSERVABLE,而Observable又分为Cold Observable(observable.toObservable())Hot Observable(observable.observe())。所以说总共有四种执行方式。但是底层都会调用到AbstractCommand.toObservable()方法。

    • execute():同步执行,返回一个单一的对象结果,发生错误时抛出异常。
    • queue():异步执行,返回一个Future对象,包含着执行结束后返回的单一结果。
    • observe():这个方法返回一个Observable对象,它代表操作的多个结果,但是已经被订阅者消费掉了。
    • toObservable():这个方法返回一个Observable对象,它代表操作的多个结果,需要咱们自己手动订阅并消费掉。

    在执行逻辑中,大量用到了RxJava,各种回调处理,看的着实头晕,感兴趣的同学可以自行阅读源码,我这里只是介绍一些关键的流程点。

    ①首先会检查是否命中缓存(toObservable方法中),命中缓存则直接返回:

    1/* try from cache first */
    2 if (requestCacheEnabled) {
    3      HystrixCommandResponseFromCache<R> fromCache = (HystrixCommandResponseFromCache<R>) requestCache.get(cacheKey);
    4       if (fromCache != null) {
    5           isResponseFromCache = true;
    6           return handleRequestCacheHitAndEmitValues(fromCache, _cmd);
    7        }
    8}
    复制代码

    ②检查断路器是否打开,如果断路器打开,则通过handleShortCircuitViaFallback直接进行fallback处理:

     1private Observable<R> applyHystrixSemantics(final AbstractCommand<R> _cmd) {
    2        executionHook.onStart(_cmd);
    3
    4        /* determine if we're allowed to execute */
    5        if (circuitBreaker.allowRequest()) {
    6        }else {
    7            return handleShortCircuitViaFallback();
    8        }
    9        ...
    10}
    复制代码

    ③检查是否用了信号量,如果用了,则判断是否被占满,占满后则抛出异常,通过handleSemaphoreRejectionViaFallback直接转到fallback中进行执行,不执行后面的逻辑。如果没用,则会返回一个默认的TryableSemaphoreNoOp.DEFAULT,在进行executionSemaphore.tryAcquire()时始终返回true。

     1if (executionSemaphore.tryAcquire()) {
    2  try {
    3    /* used to track userThreadExecutionTime */
    4    executionResult = executionResult.setInvocationStartTime(System.currentTimeMillis());
    5    return executeCommandAndObserve(_cmd)
    6            .doOnError(markExceptionThrown)
    7            .doOnTerminate(singleSemaphoreRelease)
    8            .doOnUnsubscribe(singleSemaphoreRelease);
    9    } catch (RuntimeException e) {
    10        return Observable.error(e);
    11    }
    12else {
    13    return handleSemaphoreRejectionViaFallback();
    14}
    复制代码

    ④执行命令中的逻辑

    通过重写AbstractCommand中的getExecutionObservable()方法使得下面两个命令类中的相应逻辑被调用。

    • GenericCommand中的run()方法
    • GenericObservableCommand中的construct()方法

    如果run或者construct中设置了超时时间,如果执行时间超过了阈值,则会抛出TimeoutException,或者在执行过程中抛出其他异常,都会进入fallback中进行处理逻辑。

    ⑤发生异常后执行fallback

    1   private Observable<R> getFallbackOrThrowException(final AbstractCommand<R> _cmd, 
    2         final HystrixEventType eventType,
    3         final FailureType failureType, 
    4         final String message,
    5         final Exception originalException)
     
    {
    6}
    复制代码

    最终都会调用到这个方法,咱们看看FailureType具体有哪几种类型。

    • COMMAND_EXCEPTION:执行run方法或者construct方法抛出异常时。
    • TIMEOUT:超时情况下。
    • SHORTCIRCUIT:断路器直接打开时,直接执行handleShortCircuitViaFallback方法。
    • REJECTED_THREAD_EXECUTION:线程池、请求队列被占满的情况下。
    • REJECTED_SEMAPHORE_EXECUTION:信号量占满情况下。
    • BAD_REQUEST_EXCEPTION:
    • REJECTED_SEMAPHORE_FALLBACK:

    总结

    Hystrix中大量用了RxJava,阅读源码看起来不免会觉得头晕,可以考虑在关键点打几个断点看看,不然各种回调会让你绕圈圈。不过个人觉得RxJava代码看起来还是蛮优美的,只不过有些许不适应而已,后面有时间会研究一下RxJava


    END

    转载于:https://juejin.im/post/5cbc92135188257ab6106004

    展开全文
  • 为业务容错提供隔离手段,简单理解就是,在同一个系统中,不同业务实现资源隔离,比如A业务使用自己的线程池,B业务用自己的线程池,某个业务出现线程连接问题,拖垮业务流程时候,只会影响A/B业务,而不会...

    认识hystrix

    • 为业务的容错提供隔离手段,简单理解就是,在同一个系统中,不同的业务实现资源的隔离,比如A业务使用自己的线程池,B业务用自己的线程池,某个业务出现线程连接问题,拖垮业务流程的时候,只会影响A/B业务,而不会拖垮整个应用。
    • 降级,熔断技术,服务脱机或者网络问题导致的系统不可用时的另一个容错方法

    hystrix 提供的功能

    • 线程池隔离
    • 信号量隔离
    • 熔断
    • 降级回退

    接下里就针对上面的四个功能,结合源码来进行学习。

    hystrix入门学习--如何使用

    首先添加依赖,目前已经没有开发者版本了,只有maintain版本,以maven工程为例。
    	  <dependency>
                    <groupId>com.netflix.hystrix</groupId>
                    <artifactId>hystrix-core</artifactId>
                    <version>1.5.13</version>
                </dependency>
    
    编写业务逻辑
    public class HytrixHelloBiz   extends HystrixCommand<String> {
    
        //thread group 
        protected   HytrixHelloBiz(){
            super(HystrixCommandGroupKey.Factory.asKey("wyw"));
        }
    
        @Override
        protected String run() throws Exception {
            //TODO BIZ LOGICAL
    
    
            Thread.sleep(500);
    
            return "success";
        }
    
    
        @Override
        protected  String  getFallback(){
            //TODO BIZ BUSY LOGICAL
    
            return  "error";
    
        }
    }
    
    模拟外部调用
    public static void  main(String[] args){
            HytrixHelloBiz   biz =  new HytrixHelloBiz();
            String  result = biz.execute();
            System.out.println(result);
        }
    

    随着biz中线程处理的事件越长的时候,result返回error,这里就是我们常说的降级处理,主要有fallBack接口实现,这里可以联想一下线程池中丢弃策略的的概念。

    上边就是一个hystrix的简单实用,后续进行hystrix的详细学习

    转载于:https://my.oschina.net/u/4012900/blog/2993165

    展开全文
  • hystrix原理

    2019-10-19 22:35:00
    每个服务作为轻量子服务,通过RPC实现服务间关联,将服务简单化。每个服务根据自己的需要选择技术栈,互不影响,方便开发、维护。例如S划分为a,b,c。微服务好处是有效拆分应用,实现敏捷开发和部署。微服务...

    一、hystrix 产生背景

    微服务是解决复杂服务的一个方案,在功能不变的情况下,对一个复杂的单体服务分解为多个可管理的分支。每个服务作为轻量的子服务,通过RPC实现服务间的关联,将服务简单化。每个服务根据自己的需要选择技术栈,互不影响,方便开发、维护。例如S划分为a,b,c。微服务的好处是有效的拆分应用,实现敏捷开发和部署。
    微服务一系列优势下,也给微服务的管理和稳定性带来挑战,比如一个服务依赖30个微服务,每个微服务的可用性是99.999%,在不加任何管理的情况下,该聚合服务的可用性将是99.999%的30次方=99.97%,系统的可用性直接降了两个数量级达到三个九。
    且由于依赖的传递性,很容易产生雪崩效应。如下图所示:

     
    Paste_Image.png
     
    Paste_Image.png
     
    Paste_Image.png

    一个应用中,任意一个点的不可用或者响应延时都有可能造成服务不可用
    更可怕的是,被hang住的请求会很快耗尽系统的资源,当该类请求越来越多,占用的计算机资源越来越多的时候,会导致系统瓶颈出现,造成其他的请求同样不可用,最终导致业务系统崩溃,又称:雪崩效应
    造成雪崩原因可以归结为以下三个:

    • 服务提供者不可用(硬件故障,程序Bug,缓存击穿,用户大量请求)
    • 重试加大流量(用户重试,代码逻辑重试)
    • 服务调用者不可用(同步等待造成的资源耗尽)
    • 最终的结果就是一个服务不可用导致一系列服务的不可用,而往往这种后果往往无法预料的。

    二、 hystrix实现原理

    hystrix语义为“豪猪”,具有自我保护的能力。hystrix的出现即为解决雪崩效应,它通过四个方面的机制来解决这个问题

    • 隔离(线程池隔离和信号量隔离):限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。
    • 优雅的降级机制:超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。
    • 融断:当失败率达到阀值自动触发降级(如因网络故障/超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。
    • 缓存:提供了请求缓存、请求合并实现。
    • 支持实时监控、报警、控制(修改配置)

    2.1 隔离

     
    Paste_Image.png

    (1)线程池隔离模式:使用一个线程池来存储当前的请求,线程池对请求作处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。这种方式需要为每个依赖的服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据存储到线程池队里慢慢处理)
    (2)信号量隔离模式:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,请求来先判断计数器的数值,若超过设置的最大线程个数则丢弃改类型的新请求,若不超过则执行计数操作请求来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)

    区别(两种隔离方式只能选其一):

     线程池隔离信号量隔离
    线程 与调用线程非相同线程 与调用线程相同(jetty线程)
    开销 排队、调度、上下文开销等 无线程切换,开销低
    异步 支持 不支持
    并发支持 支持(最大线程池大小) 支持(最大信号量上限)

    2.2 融断

    正常状态下,电路处于关闭状态(Closed),如果调用持续出错或者超时,电路被打开进入熔断状态(Open),后续一段时间内的所有调用都会被拒绝(Fail Fast),一段时间以后,保护器会尝试进入半熔断状态(Half-Open),允许少量请求进来尝试,如果调用仍然失败,则回到熔断状态,如果调用成功,则回到电路闭合状态;

     
    Paste_Image.png

    HystrixCircuitBreaker(断路器的具体实现):

     
    Paste_Image.png

    详细的工作流程:http://hot66hot.iteye.com/blog/2155036

    2.3 降级

    可能大家会混淆“融断”和“降级”两个概念。
    在股票市场,熔断这个词大家都不陌生,是指当股指波幅达到某个点后,交易所为控制风险采取的暂停交易措施。相应的,服务熔断一般是指软件系统中,由于某些原因使得服务出现了过载现象,为防止造成整个系统故障,从而采用的一种保护措施,所以很多地方把熔断亦称为过载保护。
    大家都见过女生旅行吧,大号的旅行箱是必备物,平常走走近处绰绰有余,但一旦出个远门,再大的箱子都白搭了,怎么办呢?常见的情景就是把物品拿出来分分堆,比了又比,最后一些非必需品的就忍痛放下了,等到下次箱子够用了,再带上用一用。而服务降级,就是这么回事,整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来。
    二者的目标是一致的,目的都是保证上游服务的稳定性。但其关注的重点并不一样,融断对下层依赖的服务并不级(或者说孰轻孰重),一旦产生故障就断掉;而降级需要对下层依赖的业务分级,把产生故障的丢了,换一个轻量级的方案,是一种退而求其次的方法。
    根据业务场景的不同,一般采用以下两种模式:
    第一种(最常用)如果服务失败,则我们通过fallback进行降级,返回静态值。

     
    Paste_Image.png

    第二种采用服务级联的模式,如果第一个服务失败,则调用备用服务,例如失败重试或者访问缓存失败再去取数据库。服务级联的目的则是尽最大努力保证返回数据的成功性,但如果考虑不充分,则有可能导致级联的服务崩溃(比如,缓存失败了,把全部流量打到数据库,瞬间导致数据库挂掉)。因此级联模式,也要慎用,增加了管理的难度。

     
    Paste_Image.png

    2.4 缓存

    不建议使用,对问题排查会造成很大的困扰,因此也不在这里讲了

    三、hystrix应用

    hystrix的运行流程如下所示:

     
    Paste_Image.png
    • 两个核心代理HystrixCommand,HystrixObservableCommand,任何依赖的服务只需要继承这两个类就可以了。其中HystrixObservableCommand使用观察者模式(不在此介绍范围之内,了解请移步RxJava)
    • HystrixCommand 可以采用同步调用和异步调用,异步返回Future对象(还未直接支持CompletebleFuture)
      如果开启了缓存,则会根据GroupKey,Commandkey以及cachedKey确定是否存在缓存(不建议使用)
    • 判断断路器是否开启,开启则直接调用getFallback,
    • 判断是否满足信号量隔离或线程池隔离的条件,如果隔离则抛异常
    • 执行run方法
    • metrics包含了一个计数器,用来计算当前服务的状态,无论是成功调用,还是抛异常都会记录数据(接下来再详细讲)
    • 执行降级策略

    3.1 代码实现

     1 public class GetInfoFromSinaiCommand extends HystrixCommand<List<PoiInfo>> {
     2     private PoiClient poiClient;
     3     private List<Integer> poiIds;
     4     private static final List<String> FIELDS = ImmutableList.of("id", "cate", "subcate");
     5 
     6     public GetInfoFromSinaiCommand(PoiClient poiClient, List<Integer> poiIds) {
     7         super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("sinai"))
     8                 //command配置
     9                 .andCommandKey(HystrixCommandKey.Factory.asKey("GetInfoFromSinaiCommand"))
    10                 .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
    11                         .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD))
    12                 .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withRequestCacheEnabled(true))
    13 
    14                 //融断器配置
    15                 .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withCircuitBreakerEnabled(true))
    16                 .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withCircuitBreakerRequestVolumeThreshold(20))
    17                 .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withCircuitBreakerSleepWindowInMilliseconds(5000))
    18                 .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withCircuitBreakerErrorThresholdPercentage(50))
    19 
    20                 //ThreadPool配置
    21                 .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("GetInfoFromSinaiCommand"))
    22                 .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(10))
    23                 .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(-1))
    24 
    25         );
    26 
    27 
    28 
    29         this.poiClient = poiClient;
    30         this.poiIds = poiIds;
    31 
    32     }
    33 
    34     @Override
    35     public List<PoiInfo> run() throws Exception {
    36         if (poiIds.isEmpty()) {
    37             return Lists.newArrayList();
    38         }
    39         List<PoiModel> pioModels = poiClient.listPois(poiIds, FIELDS);
    40         return parseResult(pioModels);
    41     }
    42 
    43     @Override
    44     protected String getCacheKey() {
    45         return String.valueOf(poiIds);
    46     }
    47 
    48     @Override
    49     protected List<PoiInfo> getFallback() {
    50         return Lists.newArrayList();
    51     }
    52 
    53     private List<PoiInfo> parseResult(List<PoiModel> poiModels) {
    54         if (poiModels == null || poiModels.isEmpty()) {
    55             return Lists.newArrayList();
    56         }
    57         List<PoiInfo> res = Lists.newArrayList();
    58         for (PoiModel poiModel : poiModels) {
    59             PoiInfo poiInfo = new PoiInfo();
    60             poiInfo.setPoiId(poiModel.getId());
    61 
    62             if (poiModel.getCate() != null) {
    63                 poiInfo.setCate(poiModel.getCate());
    64             }
    65             if (poiModel.getSubcate() != null) {
    66                 poiInfo.setSubcate(poiModel.getSubcate());
    67             }
    68             res.add(poiInfo);
    69         }
    70         return res;
    71     }
    72 }

     

    3.2 参数说明

    |参数类型|参数名|默认值|说明|
    |---|---|---|---|---|
    |command配置|executionIsolationStrategy|ExecutionIsolationStrategy.THREAD|信号隔离或线程隔离,默认:采用线程隔离,|
    || executionIsolationThreadTimeoutInMillisecond |1s|隔离时间大,即多长时间后进行重试|
    || executionIsolationSemaphoreMaxConcurrentRequests |10|使用信号量隔离时,命令调用最大的并发数,默认:10 |
    | |fallbackIsolationSemaphoreMaxConcurrentRequests |10|使用信号量隔离时,命令fallback(降级)调用最大的并发数,默认:10|
    || fallbackEnabled |true|是否开启fallback降级策略|
    || executionIsolationThreadInterruptOnTimeout |true|使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作|
    || metricsRollingStatisticalWindowInMilliseconds |10000ms|统计滚动的时间窗口,默认:10s|
    || metricsRollingStatisticalWindowBuckets |10|统计窗口的Buckets的数量,默认:10个
    || metricsRollingPercentileEnabled |true|是否开启监控统计功能,默认:true|
    || requestLogEnabled |true|是否开启请求日志|
    || requestCacheEnabled |true|是否开启请求缓存|
    |熔断器配置|circuitBreakerRequestVolumeThreshold|20|主要用在小流量|
    || circuitBreakerSleepWindowInMilliseconds | 5000ms |熔断器默认工作时间,默认:5秒.熔断器中断请求5秒后会进入半打开状态,放部分流量过去重试|
    || circuitBreakerEnabled | true |是否启用熔断器,默认true. 启动 |
    || circuitBreakerErrorThresholdPercentage | 50 |默认:50%。当出错率超过50%后熔断器启动|
    || circuitBreakerForceOpen | false |是否强制开启熔断器阻断所有请求,默认:false,不开启|
    || circuitBreakerForceClosed | false |是否允许熔断器忽略错误,默认false, 不开启|
    |线程池配置|HystrixThreadPoolProperties.Setter().withCoreSize(int value)|10|配置线程池大小,默认值10个|
    ||HystrixThreadPoolProperties.Setter().withMaxQueueSize(int value)|-1|配置线程值等待队列长度|

    3.3监控上报

    参考文章:

    本文的很多图和文字都粘贴自网上文章,没有注明引用请包涵!如有任何问题请留言或者加群,我会及时回复

    转载:https://www.jianshu.com/p/e07661b9bae8

    展开全文
  • ## 熔断原理熔断器,页脚断路器,其英文单词为:Circuit Breaker.熔断机制原理很简单,像家里电路熔断器,如果电路...不同于电路熔断只能断不能自动重连,Hystrix可以实现弹性容错,当情况好转之后,可以自动重连.这就...
  • 我们也通过一个简单的例子,知道了如何通过Hystrix技术实现自己的断路器。总的来说,使用Hystrix是非常简单的。本节我们将基于Hystrix技术来改造天气预报系统,使我们的服务在调用核心数据服务时,能够启用熔断机制...
  • Hystrix的信号量隔离是基于线程并发数量限制实现的,但是缺点是无法对慢调用自动进行降级,只能等待客户端自己超时,因此仍然可能会出现级联阻塞情况。 Sentinel 可以通过并发线程数模式流量控制来提供信号量...
  • 一、简介是一个微服务框架Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式工具(例如配置管理,服务发现Eureka,断路器Hystrix,智能路由Zuul,微代理,控制总线)。分布式系统协调导致了样板...
  • 使得程序员越来越不愿意测试自己的功能,写完了之后直接扔给测试就完事了。测试轮次一次又一次,时间不可避免浪费。</li><li>部署扩展困难 各个模块对服务器性能要求不同,有占用CPU高&#...
  • springCloud

    2018-08-09 16:54:33
    Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM云应用开发中涉及配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种...
  • 史上最简单的SpringCloud教程 | 第十三篇: 断路器聚合监控(Hystrix Turbine)(Finchley版本) 史上最简单的SpringCloud教程 | 第十四篇: Spring Cloud Gateway初体验 史上最简单的SpringCloud教程 | 第十五篇: ...
  • 史上最简单的SpringCloud教程 | 第十三篇: 断路器聚合监控(Hystrix Turbine)(Finchley版本) 史上最简单的SpringCloud教程 | 第十四篇: Spring Cloud Gateway初体验 史上最简单的SpringCloud教程 | 第十五篇: ...
  • springcloud微服务框架

    2021-02-25 10:55:23
    最近在学习springcloud微服务框架,看了很多博客和文章之后,自己模拟一个简单的业务场景搭建了一个springcloud项目。本次练习包括对springcloud核心组件:eureka、ribbon、hystrix的使用,以及feign和Gateway的简单...
  • ## 负载均衡配置都是由ribbon提供,语法如下 策略可以是系统默认也可以自己实现IRule,默认规则参考IRule及其实现类 <客户端>: ribbon: NFLoadBalancerRuleClassName: <策略全限定路径> 框架中包含了熔断器聚合监控...
  • 如果是使用Dubbo技术,那么,要在自己内部实现对外暴露接口,所有就有 - api ## 这里与 xxx-service-api 工程包名统一 - impl ## 对外暴露接口的实现类 如果是使用服务注册与发现技术,那么,写远程调用类...
  • RabbitMQ实现即时通讯居然如此简单!连后端代码都省得写了? SpringBoot官方支持任务调度框架,轻量级用起来也挺香! 如何让网站和API都支持HTTPS?在Nginx上做文章是个好选择! 还在手动整合Swagger?Swagger官方...
  • 对于方法调用者来说拿到都是一个<code>Observable,而内部的实现方式可以是同步,也可以是异步,但是调用者不用关心这个东西,无论实现怎么改,方法签名是不用变,始终返回都...
  • SpringCloud Hystrix 实现 SpringCloud超时机制、断路器模式简介 Spring Cloud Eureka HA 高可用 SpringCloud Turbine SpringCloud zuul 网关 集成 SpringCloud Conf 搭建配置中心 spring cloud- 阿波罗...
  • Maven通过xml进行依赖管理,导致整个配置文件太过臃肿,另外灵活性也不是很强,所以我采用Gradle进行项目构建和依赖管理,在FlyTour项目中我们见证了Gradle的强大,通过简单的一些配置就可以轻松的实现组件化的功能...
  • 一文带你搞懂API网关

    2020-12-28 06:45:32
    如果业务比较简单的话,可以给每个业务都分配一个独立的域名(<code>https://service.api.company.com</code>),但这种方式会有几个问题: <ul><li>每个业务都会需要鉴权、限流、权限校验等逻辑,...
  • 链路追踪:自定义traceId的方式,实现简单的链路追踪功能 多租户功能:集成Mybatis Plus,实现saas多租户功能 文件结构 matecloud -- 父项目,各模块分离,方便集成和微服务 │ ├─mate-core -- 核心通用模块,...
  • blogs plan

    2020-12-31 07:05:40
    所以写时候请按写书标准要求自己。标准就是 manning 出版社 in action 系列。 <ul><li>博客文章请以 markdown 格式放在 <code>blog/zh-cn</code> 下</li><li>目录请修改 <code>site_config/blog.js</code></...

空空如也

空空如也

1 2
收藏数 24
精华内容 9
关键字:

自己实现简单的hystrix