Hystrix
摘要
- 服务降级
- 服务熔断
- 服务限流(资源隔离)
同步等待:资源隔离、MQ解耦、不可用服务调用快速失败等。资源隔离通常指不同服务调用采用不同的线程池;不可用服务调用快速失败一般通过熔断器模式结合超时机制实现。
Hystrix 解决同步等待导致的服务雪崩问题。
高并发下,线程资源被某一服务抢用,导致其他服务也会等待线程资源释放才能获取到对应资源,从而导致资源获取变慢。
资源隔离的两种形式
- 线程池
- 信号量
服务降级
springBoot启动类
- 标注EnableHystrix注解
@HystrixCommand注解
- 参数falllback:异常报错,或者不满足设置的降级策略(例如并发线程数超过核心线程数,请求时间超过设置的最大超时时间等),都会触发服务降级,执行fallback指定的兜底方法。
@DefaultProperties 设置默认的兜底方法
处理服务端宕机,服务降级处理在客户端处理
@FeignClient中添加fallback属性
服务熔断
服务熔断,其实就是中断后续调用,快速返回给用户,解决的问题是长时间调用的服务大量占用资源,最后导致该服务挂掉,从而导致整个服务链路挂掉,这就是服务雪崩。
服务熔断解决的是:长时间的响应服务,大规模调用时,导致整个服务链路挂掉(服务雪崩)。
- 三个状态
- open:打开熔断,也就是服务调用方执行本地降级策略,不进行远程调用。
- closed:关闭了熔断,这时候服务调用方直接发起远程调用。
- half-open:一个中间状态,允许定量的服务请求直接发起远程调用。
graph LR
Open--熔断器时间窗结束-->Half-Open
Close--健康状况低于阈值-->Open
Close--健康状况高于阈值-->Close
Half-Open--调用失败-->Open
Half-Open--调用成功-->Close
- closed->open:正常情况下熔断器为closed状态,如果当前健康状况高于设定阈值,保持closed。如果当前健康状况低于设定阈值,则切换为open。
- open->half-open:当服务接口对应的熔断器为open状态,所有服务调用方调用该服务方法时全部执行本地降级方法。Hystrix提供了一种测试策略,即设置了一个时间窗口(一般设置成平均故障处理时间,也就是MTTR),从熔断器变为open状态开始的一个时间窗口内,调用该服务接口时都委托服务降级方法进行执行。如果时间超过了时间窗口,则把熔断状态从open->half-open
- half-open->closed:当熔断器为half-open状态,允许定量的服务请求。 若全部(或一定比例)的请求调用成功, 熔断器恢复到closed,否则,熔断器状态为open, 接下来的请求被禁止通过,重新记录时间窗口开始时间。
Hystrix 工作流程图
- 构建HystrixCommand对象或者HystrixObservableCommand对象。
- 调用excute或者queue方法(HystrixCommand为例)
-
Hystrix API提供了四个触发流程的方法供开发者调用,下面四个方法中前两个方法仅适用于HystrixCommand类。
-
- execute()方法,调用外部依赖只返回一个值,该方法会阻塞调用线程
-
- queue()方法,调用外部依赖只返回一个值,返回一个Future对象
-
- observe()方法,返回一个hot observable,调用该方法时直接执行command逻辑。
-
- toObservable()方法,返回一个cold observable,在subscribe返回的Observable时真正执Command逻辑
-
其中execute()方法和queue()方法是HystrixCommand类特有的,适用于外部依赖只返回一个结果的情况下。
execute()方法的实现是通过调用HystrixCommand的queue()方法获得Future,调用Future的get()方法获取最终的返回值。而无论是HystrixCommand的execute()方法还是queue()方法,最终都是通过调用toObservable()方法来实现的。只不过是HystrixCommand这两个方法返回的结果只有一个值。
-
- 是否开启缓存,并且命中缓存,是则直接返回,否则进行降级判断
- 降级判断依次为:
- 断路器是否为开启状态?
- 线程池/队列/信号量是否已被打满?
- 是否调用失败?
- 是否调用超时?
上述条件依次为否时,则执行第9步(即正常返回);否则执行服务降级逻辑,调用getFallback方法。
Hystrix 图形化Dashboard工具
第一: 配置相关依赖
<!-- hystrix dashboard 图形化监控依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
第二: 主启动类上加上 @EnableHystrixDashboard 注解 开启dashboard监控。
//加注解@EnableHystrixDashboard
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboard {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboard.class,args);
}
}
第三: 在注册中心的注册的那些服务提供者(Provider)的服务都要加上监控依赖
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
第四: 由于springcloud 升级的坑
SerlvetRegistrationBean 因为 springboot 的默认路径不是 “/hystrix.stream” 需要在被监控的项目的主启动类中配置一下下面的servlet
@Bean
public ServletRegistrationBean getServlet()
{
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
第五 : 启动项目 url为: localhost:监控服务端口/hystrix