目录
修改cloud-provider-hystrix-payment8001
服务熔断
熔断机制概述
熔断是什么?
这个概念由martin fowler 提出->Martin Fowler 博客里关于断路器的介绍
熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点的服务的调用,快速返回错误响应信息。
当检测到该节点微服务响应正常以后,恢复调用链路。(相较于服务降级返回的备用策略,服务熔断不一样的是等状况好转以后会试着恢复调用链路,回到正轨调用方案上)
在Spring Cloud框架里,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用状况,当失败的调用到一定的阈值,缺省是5秒内20次调用失败,就会启动熔断机制。
熔断机制的注解是@HystrixCommand
简单来讲,断路器有三种状态,关闭,打开,半打开。
正常的调用情况下,断路器是关闭的,当某种情况出现,比如高并发的情况下,导致系统瘫痪,断路器将打开,此时将不能进行正常调用了。此时访问量就逐渐减少,当有少量访问的时候,断路器半打开状态,断路器会试着恢复链路,少量的请求范围系统,如果能够正常运行,则恢复正常链路。
电路开关闭的确切方式:(这段话来自hystirx的GitHub 的wiki板块,How-it-Works)
- 假设请求次数到达一定的阈值
- 假设错误率错过阈值的错误率
- 然后断路器从CLOSED过渡到OPEN
- 当断路器是打开状态,会对所有的请求进行短路
- 在一段时间之后(HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds()),下一个请求被允许通过(这是HALF-OPEN状态)。如果请求失败,断路器在休眠窗口期间返回OPEN状态。如果请求成功,断路器转换为CLOSED
服务熔断实操
修改cloud-provider-hystrix-payment8001
PaymentService
忽略头上的一系列注解,这本身是一个简单的方法,输入数字,若为负数,则报错,然后被服务降级到paymentCircuitBreaker_fallback方法里面。
//服务熔断
@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 不能负数,请稍候再试,(┬_┬)/~~ id: " + id;
}
根据断路器打开的要求
我们根据circuitBreaker.enabled启用了断路器
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
通过circuitBreaker.requestVolumeThreshold规定了请求次数
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
通过sleepWindowInMilliseconds规定了时间窗口期,比如在10秒的窗口期,我们10次访问,失败率达到60%,就开启断路器。
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),
通过circuitBreaker.errorThresholdPercentage规定了失败率超过多少后开启断路器
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"),
接下来再分析分析@HystrixProperty属性里的要求,这些属性来自哪里?
HystrixCommandProperties 这个类规定了HystrixCommand注解下的HystrixProperty属性里的值。
PaymentController
/**
* 服务熔断
*
* @param id 主键
* @return
*/
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
String result = paymentService.paymentCircuitBreaker(id);
log.info("*******result:" + result);
return result;
}
测试
输入正数正常访问成功
输入负数进入了服务降级的方法中
输入多次放一首歌有,开启了短路模式,此时用正数访问也不能成功了
然后再不断输入正数,达到一定的成功率,恢复链路,能够正常访问了
熔断类型
熔断打开
请求不再进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟则进入熔断状态
熔断关闭
熔断关闭不会对服务进行熔断
熔断半开
部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断
断路器在什么情况下开始起作用
- 当满足一定阀值的时候(默认10秒内超过20个请求次数)
- 当失败率达到一定的时候(默认10秒内超过50%请求失败)
- 到达以上阀值,断路器将会开启
- 当开启的时候,所有请求都不会进行转发
- 一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。重复4和5
涉及到断路器的三个重要参数:快照时间窗口,请求总数阈值,错误百分比阈值
快照时间窗口
断路器确定是否需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗口,默认为最近的10秒
请求总数阈值
在快照时间窗内,必须满足请求总数的阈值才有资格熔断,默认是20,意味着在10秒内,如果该hystirx命令的调用次数不足20次,即使所有的请求都超时或者其他原因失败,断路器都不会打开。
错误百分比阈值
当请求总数在快照时间窗内超过了阈值,比如发生了30次调用,如果在这30次调用中,有15次发生了50%的错误百分比,在默认设定50%阈值情况下,这时候断路器打开。
Hystirx工作流程
下图来自Hystrix官网,其描述了Hystrix的工作流程
转换成流程图,如下所示:
以下部分将更详细地解释此流程:
-
构造一个
HystrixCommand
或HystrixObservableCommand
对象 -
执行命令
- 是否启用了缓存并且命中缓存?
- 断路器是否开启》?
- 是否有可用资源?(比如线程,队列)
- 执行远程调用
HystrixCommand.run()或者HystrixObservableCommand.construct()
- 报告服务健康情况
- 服务降级
- 返回结果
服务限流
鉴于Hystrix已停止更新,后面会讲解alibaba的Sentinel,但Hystrix的整个理念都非常的好,值得学习。