zoukankan      html  css  js  c++  java
  • springcloud Hystrix

    一、什么是Hystrix?

    Hystrix是Spring Cloud提供的一种带有熔断机制的框架,由于在微服务系统中同一个操作会由多个不同的微服务来共同完成,所以微服务与微服务之间会由很多相互的调用,由于在分布式环境中经常会出现某个微服务节点故障的情况,所以会由调用失败发生,而熔断器的作用就是当出现远程调用失败的时候提供一种机制来保证程序的正常运行而不会卡死在某一次调用,类似Java程序中的try-catch结构,而只有当异常发生的时候才会进入catch的代码块。
    Hystrix的特性有哪些?

    1.请求熔断: 当Hystrix Command请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open). 这时所有请求会直接失败而不会发送到后端服务. 断路器保持在开路状态一段时间后(默认5秒), 自动切换到半开路状态(HALF-OPEN).

        这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN). Hystrix的断路器就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力.

      2.服务降级:Fallback相当于是降级操作. 对于查询操作, 我们可以实现一个fallback方法, 当请求后端服务出现异常的时候, 可以使用fallback方法返回的值. fallback方法的返回值一般是设置的默认值或者来自缓存.告知后面的请求服务不可用了,不要再来了。

      3.依赖隔离(采用舱壁模式,Docker就是舱壁模式的一种):在Hystrix中, 主要通过线程池来实现资源隔离. 通常在使用的时候我们会根据调用的远程服务划分出多个线程池.比如说,一个服务调用两外两个服务,你如果调用两个服务都用一个线程池,那么如果一个服务卡在哪里,资源没被释放

       后面的请求又来了,导致后面的请求都卡在哪里等待,导致你依赖的A服务把你卡在哪里,耗尽了资源,也导致了你另外一个B服务也不可用了。这时如果依赖隔离,某一个服务调用A B两个服务,如果这时我有100个线程可用,我给A服务分配50个,给B服务分配50个,这样就算A服务挂了,

       我的B服务依然可以用。

      4.请求缓存:比如一个请求过来请求我userId=1的数据,你后面的请求也过来请求同样的数据,这时我不会继续走原来的那条请求链路了,而是把第一次请求缓存过了,把第一次的请求结果返回给后面的请求。

      5.请求合并:我依赖于某一个服务,我要调用N次,比如说查数据库的时候,我发了N条请求发了N条SQL然后拿到一堆结果,这时候我们可以把多个请求合并成一个请求,发送一个查询多条数据的SQL的请求,这样我们只需查询一次数据库,提升了效率。

    Hystrixl流程图如下:

    Hystrix流程说明:

        1:每次调用创建一个新的HystrixCommand,把依赖调用封装在run()方法中.
      2:执行execute()/queue做同步或异步调用.
      4:判断熔断器(circuit-breaker)是否打开,如果打开跳到步骤8,进行降级策略,如果关闭进入步骤5.
      5:判断线程池/队列/信号量是否跑满,如果跑满进入降级步骤8,否则继续后续步骤6.
      6:调用HystrixCommand的run方法.运行依赖逻辑
      6a:依赖逻辑调用超时,进入步骤8.
      7:判断逻辑是否调用成功
      7a:返回成功调用结果
      7b:调用出错,进入步骤8.
      8:计算熔断器状态,所有的运行状态(成功, 失败, 拒绝,超时)上报给熔断器,用于统计从而判断熔断器状态.
      9:getFallback()降级逻辑.以下四种情况将触发getFallback调用:
        (1):run()方法抛出非HystrixBadRequestException异常。
        (2):run()方法调用超时
        (3):熔断器开启拦截调用
        (4):线程池/队列/信号量是否跑满
      9a:没有实现getFallback的Command将直接抛出异常
      9b:fallback降级逻辑调用成功直接返回
      9c:降级逻辑调用失败抛出异常
      10:返回执行成功结果
     
     
    执行命令的几种方法

    Hystrix提供了4种执行命令的方法,execute()和queue() 适用于HystrixCommand对象,而observe()和toObservable()适用于HystrixObservableCommand对象。

    execute()

    以同步堵塞方式执行run(),只支持接收一个值对象。hystrix会从线程池中取一个线程来执行run(),并等待返回值。

    queue()

    以异步非阻塞方式执行run(),只支持接收一个值对象。调用queue()就直接返回一个Future对象。可通过 Future.get()拿到run()的返回结果,但Future.get()是阻塞执行的。若执行成功,Future.get()返回单个返回值。当执行失败时,如果没有重写fallback,Future.get()抛出异常。

    observe()

    事件注册前执行run()/construct(),支持接收多个值对象,取决于发射源。调用observe()会返回一个hot Observable,也就是说,调用observe()自动触发执行run()/construct(),无论是否存在订阅者。

    如果继承的是HystrixCommand,hystrix会从线程池中取一个线程以非阻塞方式执行run();如果继承的是HystrixObservableCommand,将以调用线程阻塞执行construct()。

    observe()使用方法:

        调用observe()会返回一个Observable对象
        调用这个Observable对象的subscribe()方法完成事件注册,从而获取结果

    toObservable()

    事件注册后执行run()/construct(),支持接收多个值对象,取决于发射源。调用toObservable()会返回一个cold Observable,也就是说,调用toObservable()不会立即触发执行run()/construct(),必须有订阅者订阅Observable时才会执行。

    如果继承的是HystrixCommand,hystrix会从线程池中取一个线程以非阻塞方式执行run(),调用线程不必等待run();如果继承的是HystrixObservableCommand,将以调用线程堵塞执行construct(),调用线程需等待construct()执行完才能继续往下走。

    toObservable()使用方法:

        调用observe()会返回一个Observable对象
        调用这个Observable对象的subscribe()方法完成事件注册,从而获取结果

    需注意的是,HystrixCommand也支持toObservable()和observe(),但是即使将HystrixCommand转换成Observable,它也只能发射一个值对象。只有HystrixObservableCommand才支持发射多个值对象。


        execute()实际是调用了queue().get()
        queue()实际调用了toObservable().toBlocking().toFuture()
        observe()实际调用toObservable()获得一个cold Observable,再创建一个ReplaySubject对象订阅Observable,将源Observable转化为hot Observable。因此调用observe()会自动触发执行run()/construct()。

    Hystrix总是以Observable的形式作为响应返回,不同执行命令的方法只是进行了相应的转换。
     
    Hystrix容错

    Hystrix的容错主要是通过添加容许延迟和容错方法,帮助控制这些分布式服务之间的交互。 还通过隔离服务之间的访问点,阻止它们之间的级联故障以及提供回退选项来实现这一点,从而提高系统的整体弹性。Hystrix主要提供了以下几种容错方法:

        资源隔离
        熔断
        降级

    下面介绍这几种容错机制。

    资源隔离

    资源隔离主要指对线程的隔离。Hystrix提供了两种线程隔离方式:线程池和信号量。

    线程隔离-线程池
     熔断

    熔断器简介

    现实生活中,可能大家都有注意到家庭电路中通常会安装一个保险盒,当负载过载时,保险盒中的保险丝会自动熔断,以保护电路及家里的各种电器,这就是熔断器的一个常见例子。Hystrix中的熔断器(Circuit Breaker)也是起类似作用,Hystrix在运行过程中会向每个commandKey对应的熔断器报告成功、失败、超时和拒绝的状态,熔断器维护并统计这些数据,并根据这些统计信息来决策熔断开关是否打开。如果打开,熔断后续请求,快速返回。隔一段时间(默认是5s)之后熔断器尝试半开,放入一部分流量请求进来,相当于对依赖服务进行一次健康检查,如果请求成功,熔断器关闭。

    熔断器配置

    Circuit Breaker主要包括如下6个参数:

    1、circuitBreaker.enabled

    是否启用熔断器,默认是TRUE。
    2 、circuitBreaker.forceOpen

    熔断器强制打开,始终保持打开状态,不关注熔断开关的实际状态。默认值FLASE。
    3、circuitBreaker.forceClosed
    熔断器强制关闭,始终保持关闭状态,不关注熔断开关的实际状态。默认值FLASE。

    4、circuitBreaker.errorThresholdPercentage
    错误率,默认值50%,例如一段时间(10s)内有100个请求,其中有54个超时或者异常,那么这段时间内的错误率是54%,大于了默认值50%,这种情况下会触发熔断器打开。

    5、circuitBreaker.requestVolumeThreshold

    默认值20。含义是一段时间内至少有20个请求才进行errorThresholdPercentage计算。比如一段时间了有19个请求,且这些请求全部失败了,错误率是100%,但熔断器不会打开,总请求数不满足20。

    6、circuitBreaker.sleepWindowInMilliseconds

    半开状态试探睡眠时间,默认值5000ms。如:当熔断器开启5000ms之后,会尝试放过去一部分流量进行试探,确定依赖服务是否恢复。

    熔断器工作原理

    下图展示了HystrixCircuitBreaker的工作原理:

    熔断器工作的详细过程如下:

    第一步,调用allowRequest()判断是否允许将请求提交到线程池

        如果熔断器强制打开,circuitBreaker.forceOpen为true,不允许放行,返回。
        如果熔断器强制关闭,circuitBreaker.forceClosed为true,允许放行。此外不必关注熔断器实际状态,也就是说熔断器仍然会维护统计数据和开关状态,只是不生效而已。

    第二步,调用isOpen()判断熔断器开关是否打开

        如果熔断器开关打开,进入第三步,否则继续;
        如果一个周期内总的请求数小于circuitBreaker.requestVolumeThreshold的值,允许请求放行,否则继续;
        如果一个周期内错误率小于circuitBreaker.errorThresholdPercentage的值,允许请求放行。否则,打开熔断器开关,进入第三步。

    第三步,调用allowSingleTest()判断是否允许单个请求通行,检查依赖服务是否恢复

        如果熔断器打开,且距离熔断器打开的时间或上一次试探请求放行的时间超过circuitBreaker.sleepWindowInMilliseconds的值时,熔断器器进入半开状态,允许放行一个试探请求;否则,不允许放行。

    此外,为了提供决策依据,每个熔断器默认维护了10个bucket,每秒一个bucket,当新的bucket被创建时,最旧的bucket会被抛弃。其中每个blucket维护了请求成功、失败、超时、拒绝的计数器,Hystrix负责收集并统计这些计数器。
     回退降级

    降级,通常指务高峰期,为了保证核心服务正常运行,需要停掉一些不太重要的业务,或者某些服务不可用时,执行备用逻辑从故障服务中快速失败或快速返回,以保障主体业务不受影响。Hystrix提供的降级主要是为了容错,保证当前服务不受依赖服务故障的影响,从而提高服务的健壮性。要支持回退或降级处理,可以重写HystrixCommand的getFallBack方法或HystrixObservableCommand的resumeWithFallback方法。

    Hystrix在以下几种情况下会走降级逻辑:

        执行construct()或run()抛出异常
        熔断器打开导致命令短路
        命令的线程池和队列或信号量的容量超额,命令被拒绝
        命令执行超时

    降级回退方式

    Fail Fast 快速失败

    快速失败是最普通的命令执行方法,命令没有重写降级逻辑。 如果命令执行发生任何类型的故障,它将直接抛出异常。

    Fail Silent 无声失败

    指在降级方法中通过返回null,空Map,空List或其他类似的响应来完成。
     
    转自: https://blog.csdn.net/zhuyanlin09/article/details/90368406
  • 相关阅读:
    Smart Client Architecture and Design Guide
    Duwamish密码分析篇, Part 3
    庆贺发文100篇
    .Net Distributed Application Design Guide
    New Introduction to ASP.NET 2.0 Web Parts Framework
    SPS toplevel Site Collection Administrators and Owners
    来自Ingo Rammer先生的Email关于《Advanced .Net Remoting》
    The newsletter published by Ingo Rammer
    深度探索.Net Remoting基础架构
    信道、接收器、接收链和信道接受提供程序
  • 原文地址:https://www.cnblogs.com/hellohero55/p/12730477.html
Copyright © 2011-2022 走看看