服务降级 Fallback
解决
- 生产者服务
8001超时 了:消费者调用方80不能一直卡死等待,必须有 服务降级- 生产者服务
8001宕机 了:消费者调用方80不能一直卡死等待,必须有 服务降级- 生产者服务
8001正常:消费者调用方80自己出故障或自己有要求(如自身等待时间小于服务提供者响应时间),80自身 必须有 服务降级
生产者微服务 provider8001
自身存在问题的解决
- 设置
自身调用超时时间,在设定时间内可以正常运行- 超过设置时间,需要有
兜底方法,做服务降级 Fallback
业务类
在 Service 实现类 使用 @HystrixCommand 注解,其具有如下属性:
fallbackMethod:指定要触发的兜底方法,兜底方法的形参必须和@HystrixCommand注释的方法形参一致commandProperties:触发条件,捕获什么异常时执行兜底方法- 用
@HystrixProperty来指定具体属性,如超时触发name:属性名,如超时value:属性值,如3000,表示超过 3 秒就认为超时
- 用
- 由于设置了触发降级的超时时间为
3秒,所以我们将超时方法中原先的睡3秒改为5秒,这样就一定可以触发设定的服务降级条件
主启动类
- 在主启动类添加
@EnableCircuitBreaker注解
测试
访问
localhost:8001/payment/hystrix/timeout/2分析:这个方法被我们设定为需要执行
5秒,但是我们加了8001自身超时服务降级,在第3秒,触发,并执行兜底方法,所以应当看到兜底方法的执行结果
注意
实际上这里除了设定的超时触发兜底方法,此处被 @HystrixCommand 注解的方法内发生其他异常(如被除数为0异常)也会触发兜底方法,只是用 @HystrixProperty 可以准确的指定超时时间
消费者 consumer80
注意
Hystrix 服务降级可以在 客户端 实现,也可以在 服务端 实现
- 但一般在
客户端(消费者方)实现
cloud-consumer-hystrix-order80也要更好的保护自己,实现 客户端降级保护
- 对
@HystrixComman代码的修改建议不使用热部署,而是直接重启微服务
主启动类
- 添加
@EnableHystrix注解,它包含了@EnableCircuitBreaker注解
业务类
还是使用 @HystrixCommand 注解,如法炮制,这里设定为超过 2.5 秒就认为自己调用的服务方微服务出毛病了,在客户端消费者端触发服务降级
- 写在
Controller里 consumer-order80的服务层只有接口,用OpenFeign调用provider8001微服务的实际业务逻辑
Controller
测试
- 访问
http://127.0.0.1:80/consumer/payment/hystrix/timeout/2
YAML 坑
注意:坑
可以触发我们在 客户端80 写的服务降级兜底方法
- 但可以看到触发消耗的时间大约为
1秒,跟我们设定的2.8秒不符 - 因为
OpenFeign远程调用的超时控制是基于Ribbon的,Ribbon的默认远程调用超时时间我们需要改大一点,改到5秒 - 需要开启
feign.hystrix.enable=true,否则后面全局服务降级会出问题 - 还要修改
hystrix的超时时间,也改大一点
现在客户端触发超时服务降级的时间符合我们的设定
全局服务降级
目前写法的问题:
- 每个业务方法都对应一个兜底方法,而且混在一起写,耦合度高,方法变多
- 希望有自定义的兜底方法,也希望有公用的统一的兜底方法
默认服务降级方法
直接在
客户端80Controller 上加全局默认兜底注解
@DefaultProperties(defaultFallback = "")注定一个全局默认服务降级兜底方法- 只写
@HystrixCommand注解,而不写具体fallbackMethod方法的 Controller 方法,都用默认兜底方法来兜底
- 默认兜底方法不能有形参
- 现在
time_out方法不再设置超时,而是写一个立即触发的异常- 观察异常发生后,全局服务降级兜底方法能否被触发
- 专门写了
@HystrixCommand注解的具体fallbackMethod方法的 Controller 方法,按照fallbackMethod的内容找兜底方法order80 Controller@RestController@DefaultProperties(defaultFallback = "paymentInfo_Global_FallbackMethod") //统一的降级配置 没有单独的降级 默认使用此个降级方法public class PaymentHystrixController {@Resourceprivate PaymentHystrixService paymentHystrixService;@GetMapping("/consumer/payment/hystrix/ok/{id}")public String paymentInfo_OK(@PathVariable("id") Integer id) {return paymentHystrixService.paymentInfo_OK(id);}@GetMapping("/consumer/payment/hystrix/timeout/{id}")/*@HystrixCommand(fallbackMethod = "paymentInfo_TimeoutFallbackMethod", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2800")})*/@HystrixCommandpublic String paymentInfo_TimeOut(@PathVariable("id") Integer id) {int i = 10 / 0; // 埋一个异常,观察全局服务降级兜底方法的触发return paymentHystrixService.paymentInfo_TimeOut(id);}// 超时——服务降级兜底方法private String paymentInfo_TimeoutFallbackMethod(Integer id) {return "/(ToT)/我是消费者80,调用8001支付系统繁忙,请10秒钟后重新尝试、\t";}// 下面是全局fallback方法private String paymentInfo_Global_FallbackMethod() {return "Global异常处理信息,请稍后再试, /(ToT)/";}}
业务代码降级代码分离
通配服务降级 FeignFallBack
模拟场景
- 客户端调服务端,遇到服务端直接宕机
- 在
客户端80完成服务降级处理- 只需要为
OpenFeign客户端定义的接口添加一个 服务降级处理实现类 即可实现解耦未来可能遇到的三大类异常: 运行时异常 、超时 、宕机
目前的
cloud-consumer-feign-hystrix-order80的 controller 里的方法:@GetMapping("/consumer/payment/hystrix/timeout/{id}")/*@HystrixCommand(fallbackMethod = "paymentInfo_TimeoutFallbackMethod", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2800")})*/@HystrixCommandpublic String paymentInfo_TimeOut(@PathVariable("id") Integer id) {int i = 10 / 0;return paymentHystrixService.paymentInfo_TimeOut(id);}// 超时——服务降级兜底方法private String paymentInfo_TimeoutFallbackMethod(Integer id) {return "/(ToT)/我是消费者80,调用8001支付系统繁忙,请10秒钟后重新尝试、\t";}
- 正常的 controller 接口方法和服务降级的兜底方法写在一起,高耦合,乱
修改
cloud-consumer-feign-hystrix-order80
- 目前这个客户端的
service层有一个OpenFeign远程调用服务端的PaymentHystrixService接口- 重新新建一个类
PaymentFallbackService实现上述OpenFeign Service接口,统一为接口里的方法进行异常处理/*** 服务降级统一异常兜底处理* 实现 OpenFeign 的service接口*/@Componentpublic class PaymentFallbackService implements PaymentHystrixService{@Overridepublic String paymentInfo_OK(Integer id) {return "--- PaymentFallbackService paymentInfo_OK 方法 服务降级: /(ToT)/ ";}@Overridepublic String paymentInfo_TimeOut(Integer id) {return "--- PaymentFallbackService paymentInfo_TimeOut 方法 服务降级: /(ToT)/ ";}}
- 在
OpenFeign远程调用服务端的PaymentHystrixService接口中,@FeignClient注解指定fallback属性为刚才写的统一服务降级兜底Service实现类
- 当
OpenFeign中的远程调用出错时,触发统一兜底方法OpenFeign Service@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackService.class)public interface PaymentHystrixService {@GetMapping("/payment/hystrix/ok/{id}")String paymentInfo_OK(@PathVariable("id") Integer id);@GetMapping("/payment/hystrix/timeout/{id}")String paymentInfo_TimeOut(@PathVariable("id") Integer id);}
测试
访问
http://127.0.0.1:80/consumer/payment/hystrix/ok/2
- 响应:
线程池:http-nio-8001-exec-9payment_OK, id:2 O(∩_∩)O哈哈~
访问
http://127.0.0.1:80/consumer/payment/hystrix/timeout/2
- 因为里面写了个
10 / 0必定异常,然后触发controller里写的默认兜底方法- 响应:
Global异常处理信息,请稍后再试, /(ToT)/
把
provider8001直接关了,模拟服务端宕机
- 访问
http://127.0.0.1:80/consumer/payment/hystrix/ok/2
- 应该触发
OpenFeign通配服务降级- 响应:
--- PaymentFallbackService paymentInfo_OK 方法 服务降级: /(ToT)/- 把 order80 controller 里的
10 / 0异常去掉,然后访问http://127.0.0.1:80/consumer/payment/hystrix/timeout/2
- 应该触发
OpenFeign通配服务降级- 响应:
--- PaymentFallbackService paymentInfo_TimeOut 方法 服务降级: /(ToT)/