用Hystrix保护自己

Posted 要师傅talk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用Hystrix保护自己相关的知识,希望对你有一定的参考价值。

本文将为大家介绍什么是 Hystrix,了解 Hystrix的体系架构,以及如何利用Hystrix保护自己的应用。
1背景

服务的稳定是公司可持续发展的重要基石,随着业务量的快速发展,一些平时正常运行的服务,会出现各种突发状况,而且在分布式系统中,每个服务本身又存在很多不可控的因素,比如线程池处理缓慢,导致请求超时,资源不足,导致请求被拒绝,又甚至直接服务不可用、宕机、数据库挂了、缓存挂了、消息系统挂了… 

服务进化史                                                                                                             
传统单体应用
模块化部署/OSGi
远程调用(RPC, HTTP)
分布式微服务
分布式单体应用( )


用Hystrix保护自己

问题来了

网络通信不可靠

三态(成功、失败、未知)

时钟不可靠

协调困难

无法感知崩溃和超时

CAP/拜占庭



常见事故现场

用Hystrix保护自己


程序员的日常


成功,失败,异常,超时,重试,短路,限流,削峰,幂等性,队列打满,内存溢出,缓存打穿,丢数据,修数据,应用雪崩……


用Hystrix保护自己



 怎么破?


永远不要相信你的上下游

搞清楚你使用的工具原理

关注业界最佳实践

任何复杂问题都可以通过引入一个间接层来解决

 



理解client的运行机制

在理解上下游的机制后合理设置自己的超时时间

Failover,Failsafe,Failfast,Failback,Forking

熔断降级

限流(限总量、限速率、限并发)

异步化/队列



2Hystrix来了

用Hystrix保护自己


Hystrix 帮你搞定


依赖的服务出现延迟或失败的时候,提供保护和控制

分布式系统中,防止级联失败

Failfast,让系统快速恢复

Failback,提供失败回退优雅降级机制

熔断器设计模式的可靠实现

提供近实时的监控、报警和运维控制机制


Hystrix 工作流程



用Hystrix保护自己


下面将更详细的解析每一个步骤都发生哪些动作:


1. 构建一个HystrixCommand或者HystrixObservableCommand对象。


第一步就是构建一个HystrixCommand或者HystrixObservableCommand对象,该对象将代表你的一个依赖请求,向构造函数中传入请求依赖所需要的参数。


如果构建HystrixCommand中的依赖返回单个响应,例如:

HystrixCommand command = new HystrixCommand(arg1, arg2);


如果依赖需要返回一个Observable来发射响应,就需要通过构建HystrixObservableCommand对象来完成,例如:

HystrixObservableCommand command = new HystrixObservableCommand(arg1, arg2);


2. 执行命令


有4种方式可以执行一个Hystrix命令。

1) execute()—该方法是阻塞的,从依赖请求中接收到单个响应(或者出错时抛出异常)。

2) queue()—从依赖请求中返回一个包含单个响应的Future对象。


3) observe()—订阅一个从依赖请求中返回的代表响应的Observable对象。

4) toObservable()—返回一个Observable对象,只有当你订阅它时,它才会执行Hystrix命令并发射响应。


K value = command.execute();Future<K> fValue = command.queue();Observable<K> ohValue = command.observe(); //hot observableObservable<K> ocValue = command.toObservable();    //cold observable


同步调用方法execute()实际上就是调用queue().get()方法,queue()方法的调用的是toObservable().toBlocking().toFuture().也就是说,最终每一个HystrixCommand都是通过Observable来实现的,即使这些命令仅仅是返回一个简单的单个值。


3. 响应是否被缓存


如果这个命令的请求缓存已经开启,并且本次请求的响应已经存在于缓存中,那么就会立即返回一个包含缓存响应的Observable


4. 回路器是否打开

当命令执行执行时,Hystrix会检查回路器是否被打开。

如果回路器被打开(或者tripped),那么Hystrix就不会再执行命名,而是直接路由到第8步,获取fallback方法,并执行fallback逻辑。

如果回路器关闭,那么将进入第5步,检查是否有足够的容量来执行任务。(其中容量包括线程池的容量,队列的容量等等)。

5. 线程池、队列、信号量是否已满

如果与该命令相关的线程池或者队列已经满了,那么Hystrix就不会再执行命令,而是立即跳到第8步,执行fallback逻辑。

6. HystrixObservableCommand.construct() or HystrixCommand.run()

在这里,Hystrix通过为此目的编写的方法(以下之一)调用对依赖项的请求:

- HystrixCommand.run()返回单个响应或引发异常

HystrixObservableCommand.construct()返回一个Observable,它发出响应或发送onError通知

如果run()或Construct()方法超过了命令的超时值,则该线程将引发TimeoutException(如果命令本身不在其自己的线程中运行,则该线程将抛出单独的计时器线程)。 在那种情况下,Hystrix通过8路由响应。获取Fallback,如果该方法没有取消/中断,它将丢弃最终的返回值run()或Construct()方法。

7. 计算回路指标[Circuit Health]

Hystrix会报告成功、失败、拒绝和超时的指标给回路器,回路器包含了一系列的滑动窗口数据,并通过该数据进行统计。

它使用这些统计数据来决定回路器是否应该熔断,如果需要熔断,将在一定的时间内不在请求依赖[短路请求],当再一次检查请求的健康的话会重新关闭回路器。


8. 获取FallBack

当命令执行失败时,Hystrix会尝试执行自定义的Fallback逻辑:

1) 当construct()或者run()方法执行过程中抛出异常。

2) 当回路器打开,命令的执行进入了熔断状态。

3) 当命令执行的线程池和队列或者信号量已经满容。

4) 命令执行超时。


9. 返回成功的Response

如果Hystrix命令成功执行,它将以Observable的形式将一个或多个响应返回给调用方。

根据您在上面的步骤2中调用命令的方式,此Observable可能会在返回给您之前进行转换

用Hystrix保护自己



线程池与信号量



• 线程池隔离机制,⽤于IO依赖,⽹络请求

• 信号量隔离,⽤于应⽤内部的并发控制

用Hystrix保护自己

类型 优点 不足 适用
线程 支持排队和超时、支持异步调用 线程调用和切换产生额外开销 不受信客户(比如三方服务稳定性是无法推测的)
信号量 轻量且无额外开销 不支持任务排队和超时,不支持异步 受信客户、高频高速调用服务(网关、cache)

3实战 - Spring Boot + Dubbo + Hystrix

配置spring-cloud-starter-netflix-hystrix

添加pom依赖

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

然后在Application类上增加@EnableHystrix来启用Hystrix starter:

@SpringBootApplication@EnableHystrixpublic class ProviderApplication {

配置Provider端

在Dubbo的Provider上增加@HystrixCommand配置,这样子调用就会经过Hystrix代理。

@Servicepublic class HelloServiceImpl implements HelloService { @HystrixCommand(commandProperties = {                      @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),  //窗口期内, 失败10次断路器打开                      @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),  //断路器5s恢复, 默认10s                      @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "10"),  //出错百分比阈值, 当达到此阈值后, 开始短路. 默认 50%                      @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")  //超时时间为2s                    }) @Override public String sayHello(String name) { // System.out.println("async provider received: " + name); // return "annotation: hello, " + name; throw new RuntimeException("Exception to show hystrix enabled."); }}

配置Consumer端

对于Consumer端,则可以增加一层method调用,并在method上配置@HystrixCommand。当调用出错时,会走到fallbackMethod = "reliable"的调用里。

@Referenceprivate HelloService demoService;
@HystrixCommand(fallbackMethod = "reliable")public String doSayHello(String name) { return demoService.sayHello(name);}public String reliable(String name) { return "hystrix fallback value";}

上述配置实际运行效果: 



监控 - Dashboard

Hystrix除了实现容错之外,还提供了近乎实时的监控。Hystrix Command和HystrixObservableCommand在执行时,会会生成执行结果和运行指标,比如每秒的请求数和成功数等,这些监控数据对于分析系统请求的调用情况很有用。

下图是Hystrix运行时可以监控的维度、指标


最后

啰嗦了一大堆,从代码看,些许有些侵入性,但是毫无副作用。

在实际场景中,合理利用熔断器,针对不同粒度(服务/接口),我们会降低”修数据、三方服务挂了……“带来的困扰,提升服务质量。


以上是关于用Hystrix保护自己的主要内容,如果未能解决你的问题,请参考以下文章

Hystrix是个什么玩意儿

springcloud报错-------关于 hystrix 的异常 FallbackDefinitionException:fallback method wasn't found(代码片段

Hystrix是个什么玩意儿

Hystrix在工作中你至少需要知道的!--Ⅰ

Hystrix 框架

Spring cloud hystrix 服务容错保护