目录
1. Hystrix概述
1.1 背景
复杂分布式体系架构的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败。而高并发的依赖失败时如果没有隔离措施,当前应用服务就有被拖垮的风险。对依赖做隔离,Hystrix就是处理依赖隔离的框架,同时也是可以帮我们做依赖服务的治理和监控。
1.2 使用场景
在一个分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,如何能够保证在一个依赖出问题的情况下,不会导致整体服务失败,这个就是Hystrix需要做的事情。Hystrix提供了熔断、隔离、Fallback、cache、监控等功能,能够在一个、或多个依赖同时出现问题时保证系统依然可用。
2. Hystrix重要概念
2.1 服务降级
1) 服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示(fallback)。
2) 程序运行异常、响应超时、服务熔断出发服务降级、线程池/信号量已满。
简而言之,就是尽可能的把系统资源让给优先级高的服务。由于资源有限,而请求是无限的,如果在并发高峰期,不做服务降级处理,一方面肯定会影响整体服务的性能,严重的话可能会导致宕机某些重要的服务不可用。所以,一般在高峰期,为了保证网站核心功能服务的可用性,都要对某些服务降级处理。
2.2 服务熔断
1) 熔断关闭状态(Closed)。服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制。
2) 熔断开启状态(Open)。在固定时间内(Hystrix默认是10秒),接口调用出错比率达到一个阈值(Hystrix默认为50%),会进入熔断开启状态。进入熔断状态后, 后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法。
3) 半熔断状态(Half-Open)。在进入熔断开启状态一段时间之后(Hystrix默认是5秒),熔断器会进入半熔断状态。所谓半熔断就是尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断开启状态。
2.3 服务限流
1) 通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到限制速率就可以拒绝服务、等待、降级。
2) 常用的限流算法有滑动计数、漏斗限流和令牌桶限流三种。
-
滑动计数限流
:按时间片(比如 1 秒)定义滑动窗口,计数器记录当前窗口的请求次数,达到阈值就限流,窗口滑动后计数器归零。可采用循环队列数据结构实现。 -
漏斗限流
:维护一个队列,所有请求进队列,按 FIFO 服务,队满溢出则丢弃请求。 -
令牌桶限流
:按固定速率往桶中存入令牌,服务前先从桶中取令牌,取到令牌才服务。
3. Hystrix案例
以下案例代码的
Github地址
。
三个modules分别是:cloud-eureka-server7001,cloud-provider-hystrix-payment8001,cloud-consumer-feign-hystrix-order80。
3.1 服务降级
设置自身调用超时时间的峰值,峰值内正常运行,超过了需要兜底的方法处理,作服务降级(fallback)。
1) cloud-provider-hystrix-payment8001的fallback。
- 最简便的是直接在com.bas.springcloud.controller.PaymentController接口加上@HystrixCommand。
- 主启动类加上@EnableCircuitBreaker。
- 一旦调用服务方法失败后自动调用@HystrixCommand中申明的fallback方法。
@GetMapping("/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentInfo_TimeoutHandler",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public String paymentInfo_Timeout(@PathVariable("id") Integer id) {
String result = paymentService.paymentInfo_Timeout(id);
log.info("*****result: " + result);
return result;
}
public String paymentInfo_TimeoutHandler(Integer id) {
return "/(ToT)/调用支付接口超时或异常、\t" + "\t当前线程池名字" + Thread.currentThread().getName();
}
@SpringBootApplication
@EnableEurekaClient
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class,args);
}
}
测试结果(因为设置了3s最长等待时长,而service里面休眠3s+其他步骤就大于3s了,所以转到fallback):
注
:先启动cloud-eureka-server7001。
2) cloud-consumer-feign-hystrix-order80。
- 主启动类加上@EnableHystrix。
- YML加上以下配置:
feign:
hystrix:
enabled: true
@HystrixCommand(fallbackMethod = "paymentInfo_TimeoutHandler",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000")
})
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id") Integer id){
String result = paymentHystrixService.paymentInfo_Timeout(id);
return result;
}
public String paymentInfo_TimeoutHandler(Integer id) {
return "/(ToT)/我是消费者80,调用8001支付系统繁忙,请10秒钟后重新尝试、\t";
}
@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class OrderHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class,args);
}
}
测试结果:
注
:
- 顺序启动cloud-eureka-server7001, cloud-provider-hystrix-payment8001,最后再启动cloud-consumer-feign-hystrix-order80。
-
@EnableHystrix注解与@EnableCircuitBreaker的区别
。
3) 配置defaultFallback(cloud-consumer-feign-hystrix-order80)。
- OrderHystrixController加上@DefaultProperties(defaultFallback = “paymentInfo_Global_FallbackMethod”)和paymentInfo_Global_FallbackMethod()。
- paymentInfo_Timeout只需要配置@HystrixCommand。
- 创建PaymentHystrixService实现类PaymentFallbackServiceImpl。
- PaymentHystrixService加上@FeignClient(value = “CLOUD-PROVIDER-HYSTRIX-PAYMENT”, fallback = PaymentFallbackServiceImpl.class)。
- YML加上以下配置:
feign:
hystrix:
enabled: true
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackServiceImpl.class)
public interface PaymentHystrixService {
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id") Integer id);
}
@Service
public class PaymentFallbackServiceImpl implements PaymentHystrixService {
@Override
public String paymentInfo_OK(Integer id) {
return "----PaymentFallbackService fall back paymentInfo_OK,o(╥﹏╥)o";
}
@Override
public String paymentInfo_Timeout(Integer id) {
return "----PaymentFallbackService fall back paymentInfo_Timeout,o(╥﹏╥)o";
}
}
测试结果(关闭cloud-provider-hystrix-payment8001再访问cloud-consumer-feign-hystrix-order80的接口也能友好得到响应而不是500错误):
关闭8001前:
关闭8001后 :
3.2 服务熔断
熔断机制是应对雪崩效应的一种微服务链路保护机制。当某个微服务不可用或者响应时间太长时,会进行服务降级,进而熔断该节点微服务的调用,快速返回“错误”的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现,Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是
5秒内调用20次,如果失败,就会启动熔断机制
。
1) 熔断类型。
- 熔断打开:请求不再进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟则进入半熔断状态。
- 熔断半开:部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断。
- 熔断关闭:熔断关闭不会对服务进行熔断。
2) 断路器开启或者关闭的条件。
- 当满足一定的阈值的时候(默认10秒内超过20个请求次数)。
- 当失败率达到一定的时候(默认10秒内超过50%请求失败)。
- 到达以上阈值,断路器将会开启,所有请求都不会进行转发。
- 一段时间之后,默认是5秒,这个断路器是半开状态,会让其中一个请求进行转发,如果成功,断路器会关闭,若失败,继续开启,重复等待判断直至关闭。
3) 修改cloud-provider-hystrix-payment8001。
- PaymentService增加paymentCircuitBreaker()和@HystrixCommand相关的熔断配置。
- PaymentController增加paymentCircuitBreaker()接口。
// 服务熔断
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), //请求数达到后才计算
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), //休眠时间窗
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), //错误率达到多少跳闸
})
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
if(id < 0){
throw new RuntimeException("****id 不能为负数");
}
String serialNumber = IdUtil.simpleUUID();
return Thread.currentThread().getName() + "\t" + "调用成功,流水号:" + serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){
return "id 不能为负数,请稍后再试, o(╥﹏╥)o id: " + id;
}
测试结果(多次错误后,然后慢慢正确,发现刚开始不满足条件,后面就算是正确的访问也会报错,需要过会才能恢复正常):
成功:
失败:
多次失败后成功的访问也会变成失败的响应:
4) HystrixProperty相关参数。
-
快照时间窗:断路器判断是否需要打开错误数据记录,统计的时间范围即为快照时间窗,默认为最近 10 秒。
-
请求总数下限:在快照时间窗内,请求总数必须满足下限设置才会有资格熔断,默认为 20 次,意味着 10 秒内该 hystrix 命令的调用不足 20 次,即使所有请求都是失败的,断路器都不会打开。
-
错误百分比下限:请求总数在快照时间窗内超过了下限,比如发生 30 次调用,发生了 16 次超时异常,也就是超过百分之 50% 的错误百分比,在默认错误百分比下限 50% 设定情况下,断路器将会打开。
5) 熔断恢复。
断路器打开状态后,降级逻辑取代主逻辑,而Hystrix 提供了自动恢复功能,当断路器打开,对主逻辑进行熔断之后,Hystrix 会启动一个休眠时间窗,在这个时间窗内,降级逻辑会临时的替代主逻辑,休眠时间窗结束后,断路器变为半开状态,释放一次请求到主逻辑,如果主逻辑处理正常,断路器将关闭,否则断路器继续进入打开状态,休眠时间窗重新计时。
3.3 服务限流
由于现在服务限流基本上用的是alibaba的sentinel,所以就不做总结了。
附:
1)
尚硅谷的Springcloud网课
。