能让程序员涨薪 5K 的 Hystrix 核心工作原理,你真的不打算学吗?
Hystrix 的核心工作原理
Hystrix 的本质作用是当系统资源过载(Over Load Control)时提供服务状态保护机制,包括下面四个方面。
● 熔断:当失败率达到阈值时自动触发降级(如因网络故障或超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。
● 隔离(线程池隔离和信号量隔离):限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他调用。
● 降级:超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据,做到优雅降级。
● 缓存:提供了请求缓存、请求合并的实现方法。
Hystrix——熔断
熔断器的原理很简单,可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费 CPU 时间去等到长时间的超时产生。熔断器也可以使应用程序诊断错误是否已经修正,如果已经修正,应用程序会再次尝试调用操作。
熔断器就像是那些容易导致错误的操作的一种代理。这种代理能够记录最近调用发生错误的次数,然后决定允许操作继续或者立即返回错误。熔断器开关相互转换的逻辑如下图所示。
Hystrix 中的熔断器(Circuit Breaker)也起到这样的作用,Hystrix 在运行过程中会向每个 CommandKey 对应的熔断器报告成功、失败、超时和拒绝的状态,熔断器维护并计算统计的数据,根据这些统计信息来确定是否打开。如果打开,后续的请求都会被截断(不再执行 run 方法里的内容,直接执行 fallback 方法里的内容)。然后隔一段时间(默认是 5s),尝试半开,放一部分请求进来,相当于对依赖服务进行一次健康检查,如果服务没问题,熔断器关闭,随后完全恢复调用。
Hystrix——隔离
对于微服务系统来说,一个从客户端发来的 HTTP 请求往往途径众多微服务,在处于高流量状态下,如果其中一个服务器资源出现饱和状态,就会影响上游系统。如下图所示,Hystrix 可以将服务调用包裹在 HystrixCommand 中,每一个 HystrixCommand 都维护着一个线程池,从而隔离服务,当一个服务产生延迟时,其“吞噬”的资源也只会限定在该 HystrixCommand 内(比如至多只会占用 N 个线程资源),而不会对全局造成影响。
Hystrix 的隔离主要是为每个依赖组件提供一个隔离的线程环境,有两种隔离模式。
● 线程池隔离模式:使用一个线程池来存储当前的请求。线程池对请求做处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。这种方式需要为每个依赖的服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据存储到线程池里慢慢处理)。
● 信号量隔离模式:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,请求到来时先判断计数器的数值,若超过设置的最大线程个数,则丢弃该类型的新请求,若不超过,则执行计数操作,请求到来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)。
两种隔离模式的主要区别如下表所示。
Hystrix 隔离策略相关的参数如下。
●execution.isolation.strategy=THREAD|SEMAPHORE:设置线程或信号量隔离模式。
●hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:设置隔离模式的超时时间,默认值是 1000ms。
●execution.isolation.semaphore.maxConcurrentRequests :设置在使用时允许到 HystrixCommand.run 方法的最大请求数,默认值是 10。
● execution.timeout.enabled:设置 HystrixCommand.run 方法执行时是否开启超时设置,默认开启。
●execution.isolation.thread.interruptOnTimeout:发生超时时是否中断 HystrixCommand.run 方法,默认是 true。
●execution.isolation.thread.interruptOnCancel:取消时是否中断 HystrixCommand.run 方法,默认是 false。
Hystrix——降级
所谓降级,就是指在 Hystrix 执行非核心链路功能失败的情况下,我们如何处理,比如我们返回默认值等。如果我们要回退或者降级处理 , 代 码 上 需 要 实 现 HystrixCommand.getFallback 方 法 或 者 HystrixObservableCommand 方法。
Netflix 的 Hystrix 对微服务降级处理实现提供两种方式:
● 通过添加注解 @HystrixCommand 方式来实现。
● 通过继承 HystrixCommand 类来实现。
1.使用 @HystrixCommand 注解实现服务降级
使用注解可以最小限度地侵入代码,可以快速让原来的功能支持服 务 降 级 , 使 用 时 仅 需 在 要 进 行 服 务 降 级 处 理 的 方 法 上 增 加 @HystrixCommand 注解即可,并通过 fallbackMethod 属性设置在降级处理时所使用的方法,然后在降级方法中实现服务降级处理。需要注意:通过 fallbackMethod 属性所指定的方法要与原方法具有相同的方法签名,否则降级会失败。下面是 @HystrixCommand 的参数说明。
● groupKey:设置 HystrixCommand 分组的名称。
● commandKey:设置 HystrixCommand 的名称。
● threadPollKey:设置 HystrixCommand 执行线程池的名称。
● fallbackMethod:设置 HystrixCommand 服务降级所使用的方法
名称,注意该方法需要与原方法定义在同一个类中,并且方法签名也要一致。
● commandProperties:设置 HystrixCommand 属性,例如断路器失败百分比、断路器时间容器大小等。
● ignoreException:设置 HystrixCommand 执行服务降级处理时需要忽略的异常,当出现异常时不会执行服务降级处理。
● observableExecutionMode : 设 置 HystrixCommand 执 行 的 方式。
● defaultFallback:设置 HystrixCommand 默认的服务降级处理方 法 , 如 果 同 时 设 定 fallbackMethod 属 性 , 会 优 先 使 用 fallbackMethod 属性所指定的方法。该属性所指定的方法没有参数,需要注意返回值与原方法返回值的兼容性。
2.继承 HystrixCommand 类实现服务降级
除使用注解方式来完成服务降级实现外,Hystrix 还提供了两个对象 来 支 持 服 务 降 级 实 现 处 理 : HystrixCommand 和 HystrixObserableCommand 。 如 果 继 承 HystrixCommand 则 需 要 实 现 getFallback 方法,代码如下:
HystrixObserableCommand 用于所依赖服务返回多个操作结果的时候,在实现服务降级时,如果是继承 HystrixObserableCommand,则需要实现 resumeWithFallback 方法,代码如下。
Hystrix——缓存
Hystrix 有两种方式来应对高并发场景,分别是请求缓存与请求合并缓存。请求缓存是在同一请求多次访问中保证只调用一次这个服务提供者的接口,同一请求第一次的结果会被缓存,保证同一请求多次访问返回结果相同。
Hystrix 的缓存实现方式主要有两种:继承方式和注解方式,用得比较多的方式是注解方式,因为注解方式开发快而且相对简单,如下表所示。
1.使用 @CacheResult 开启请求缓存功能
2.使用 CacheKey 开启缓存
3.通过 @CacheRemove 注解来实现失效缓存清理功能
Hystrix 的工作流程
Hystrix 使用 RxJava 作为响应式的编程框架。这里我们简单介绍一下 Hystrix 的工作流程,一个简化版本的 Hystrix 执行流程如下图所示。
首先,构造一个 HystrixCommand 或 HystrixObservableCommand 对象。
● 如果期望依赖项返回单个响应,则构造一个 HystrixCommand 对象,代码如下:
● 如果期望依赖项返回发出响应的可观察对象,则构造一个 HystrixObservableComman 对象,代码如下:
有 4 种方法可以执行 Hystrix 命令(前两种方法只适用于简单的 HystrixCommand 对象,不适用于 HystrixObservableCommand 对象)。
● execute:该方法与 queue 方法以相同的方式获取一个 Future 对象,然后在这个 Future 上调用 get 方法来获取可观察对象发出的单个值。
● queue:该方法将可观察对象转换为 BlockingObservable 对象,以便将其转换为 Future 对象,然后返回此 Future 对象。
● observe:该方法可以立即订阅可观察对象,并开始执行命令的流。返回一个可观察对象,当订阅该对象时,它将重新产生结果并通知订阅者。
● toObservable:该方法返回的可观察值不变,需要订阅后才能真正开始执行命令流程。
下面是 Hystrix 的具体执行逻辑。
1.构造 Hystrix 命令
构造一个 HystrixCommand 或 HystrixObservableCommand 对象,用于封装请求并在构造方法中配置请求被执行需要的参数。
2.执行 Hystrix 命令
根据上文中提供的 4 种方式执行命令。
3.判断是否缓存了响应
如果你为命令启用了请求缓存,并且在缓存中命中了可用请求的响应,则缓存的响应将立即以可观察到的形式返回。
4.判断熔断电路是否打开
当执行命令时,Hystrix 将与断路器一起检查熔断电路是否打开。
如果熔断电路打开,那么 Hystrix 将不执行命令并回退。如果熔断电路关闭,则继续执行,检查是否有可用的容量来运行命令。
5.线程池、队列、信号量是否已满
如果与命令关联的线程池和队列(或信号量,如果不在线程中运行)已满,那么 Hystrix 将不执行命令,执行逻辑跳转到第 7 步。
6.计算电路健康状态
执行 HystrixObservableCommand.construct 或 HystrixCommand.run 方法,Hystrix 向断路器报告成功、失败、拒绝或超时,如果执行逻辑失败或者超,则执行逻辑跳转第 7 步;否则执行逻辑跳转到第 8 步;
7.回退
Hystrix 试图恢复你的回滚命令,并执行回退逻辑或者 fallback 备用逻辑。
8.返回成功的响应如果 Hystrix 命令成功,它将以可观察到的形式返回响应给调用者。
评论