Hystrix官方文档: https://github.com/Netflix/Hystrix/wiki#what
在一个分布式系统中,必然会有部分系统的调用会失败。Hystrix是一个通过添加超时容错和失败容错逻辑来帮助你控制这些分布式系统的交互。Hystrix通过隔离服务之间的访问,阻止他们之间的级联故障以及提供后背选项来实现这些,所有新而这些都用来提高系统的整体弹性。
Hystrix被设计用来解决一下几个方面
通过第三方(一般来源网络)的调用,给与保护和控制延迟和失败。
在复杂的分布式系统中复制级联失败。
快速失败和修复。
在可能的情况下,回滚挥着优雅的失败。
实现几乎实时监控,警报和操作控制。
复杂的分布式体系结构中的应用程序具有许多依赖关系,每个依赖关系都会在某些时候不可避免的失败。如果主机应用程序未与这些外部的故障隔离,那么可能会被这些故障拖垮。
例如:一个依赖30个SOA服务的系统,每个服务99.99%可用。
99.99%的30次方 ≈ 99.7%
0.3% 意味着一亿次请求 会有 3,000,00次失败
换算成时间大约每月有2个小时服务不稳定.
随着服务依赖数量的变多,服务不稳定的概率会成指数性提高.
而实际中可能更糟糕。
设计详解(命令模式)
4.1、流程图
(可点击查看大图)
流程说明
构造一个HystrixCommand或者HystrixObserverCommand对象,把需要调用的依赖放在run()中
执行execute/queue做同步或者异步执行
是否做了缓存
熔断是否打开
线程池/队列/信号量是否满了
调用run()或者construct()
计算熔断健康度(成功,失败,拒绝,超时)的数据,上报给熔断器,用于统计从而判断熔断器状态,可以根据这些数据来决定是否进行熔断,例如:错误率在80%以上,接口等待超过预定的时间等。
获取Fallback,如果fallback失败,系统报错,所以要尽量防止fallback报错,当然也可以在fallback上加上一层fallback
返回执行结果
下图显示了HystrixCommand或者HystrixObserverCommand如何与HystrixCircuitBreaker及哦啊胡及其逻辑和决策流程。包括计数器在断路器中的行为方式。
熔断行为
断路器打开还是关闭的步骤如下
假定请求的量超过预定的阈值(circuitBreakerRequestVolumeThreshold)
再假定错误百分比超过了设定的百分比(circuitBreakerErrorThresholdPercentage)
断路器会从close状态到open状态
当打开的状态,会短路所有针对该断路器的请求
过了一定时间(circuitBreakerSleepWindowInMilliseconds(短路超过一定时间会重新去请求)),下一个请求将通过,不会被短路(当前是half-open状态)。如果这个请求失败了,则断路器在睡眠窗口期间返回open状态,如果请求成功,则断路器返回close状态,并重新回到第一步逻辑判断。
Hystrix使用璧仓模式来隔离彼此的依赖关系,并限制对其中任何一个的并发访问。
未使用隔离前
客户端(第三方,网络调用等)依赖和请求线程运行在不同的线程上,这个将他们从调用线程隔离开来,这样调用者就可以从一个耗时太长的依赖中隔离。如下图所示,也可以为不同的请求开启不同的线程池,彼此之间不相互干扰。
(注:上图右边表示的是信号量模式)
1、线程隔离的好处:
整个应用的即是在客户端调用失效的情况下也能健康的运行,线程池能够保证这个线程下面的失效不会影响应用其他部分的运行
当失效的客户端调用回复的时候,这个线程池也会被清理并且应用会立马回复健康,比tomcat那种长时间的恢复要好很多
简而言之,线程隔离能够允许在不引起中断的情况下优雅的处理第三方调用的各种问题。
2、线程隔离的缺点
主要缺点是增加了上下文切换的开销,每个明亮的执行都涉及到队列,调度和上下文切换。不过NetFix在设计这个系统的时候,已经决定接受这笔开销,以换取他的好处。
你可以使用信号量(或者计数器)来限制当前依赖调用的并发数,而不是使用线程池或者队列。如果客户端是可信的,且能快速返回,可以使用信号量来代替线程隔离,降低开销。信号量的大小可以动态调节,线程池却不行。
HystrixCommand和HystrixObserverCommand提供信号量隔离在下面两个地方:
Fallback:当Hystrix检索fallback的时候,他心总是调用tomcat线程上执行此操作
如果你设置execution.isolation.strategy为SEMAPHORE的时候,Hystrix会使用信号量代替线程池去限制当前调用Command的并发数。
设置某个时间内的请求,合并为一个发送,例如:id和ids参数
Hystrix仪表盘
主要用来实时监控Hystrix的各项指标信息。通过Hystrix DashBoard反馈的实时信息,可以帮助我们快速防线系统中存在的问题,从而及时地采取对应措施。
开启仪表盘
1、在服务实例中新增spring-boot-starter-actuator,监控模块已开启监控相关的端点,并且映入断路器依赖:spring-cloud-starter-hystrix
2、确保在服务实例的主类中已经使用了@EnableCircuitBreaker注解,开启了断路器功能。
官方使用案例(包含了以上每种方式的案例):https://github.com/Netflix/Hystrix/wiki/How-To-Use#Fallback
简单示例:
/**
* @author haozq
* Date: 2018/7/19 上午9:44
*/
public class MyHystrixCommand extends HystrixCommand {
protected MyHystrixCommand(String groupKey) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey)));
}
@Override
protected String run() throws Exception {
//实际调用外部的地方
return "reality invoke。";
}
@Override
protected String getFallback() {
//run抛出异常,或者调用超时之后调用fallback
return "invoke failed。";
}
public static void main(String args[]){
MyHystrixCommand hystrixCommand = new MyHystrixCommand("myCommand");
System.out.println(hystrixCommand.execute());
}
}
输出:
reality invoke。
注解方式:
@RequestMapping("get-demo1-test")
@HystrixCommand(fallbackMethod = "fallback", groupKey = "userGroup")
public String getDemo1Name() throws InterruptedException {
//测试重试机制
int sleepTime = new Random().nextInt(300);
Thread.sleep(sleepTime);
return demo1Service.getAppName();
}
public String fallback(Throwable t) {
System.out.println("erroe: " + t.getMessage());
return "error";
}
几个主要的配置信息:在构造方法中通过Setter设置
1.1、execution.isolation. thread.timeoutinMilliseconds: 该属性用来配 置HystrixCommand执行的超时时间, 单位为毫秒。当HystrixCommand执行 时间超过该配置值之后, Hystrix会将该执行命令标记为TIMEOUT并进入服务降级 处理逻辑。默认值1000
1.2、execution.isolation.semaphore.maxConcurrentRequests:当HystrixCommand的隔离策略使用信号量的时候,该属性用来配置信号量的大小(并发请求数)。 当最大并发请求数达到该设置值时, 后续的请求将会被拒绝。默认值10
1.3、circuitBreaker.requestVolumeThreshold该属性设置滚动窗口中将使断路器跳闸的最小请求数量,默认值:20
1.4、circuitBreaker.sleepWindowInMilliseconds 断路器跳闸后,在此值的时间的内,hystrix会拒绝新的请求,只有过了这个时间断路器才会打开闸门
默认值:5000
1.5、circuitBreaker.errorThresholdPercentage 设置失败百分比的阈值。如果失败比率超过这个值,则断路器跳闸并且进入fallback逻辑
默认值:50
1.6、metrics.rollingStats.timeInMilliseconds 滚动窗口时间大小,默认10s