服务降级 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
的超时时间,也改大一点
现在客户端触发超时服务降级的时间符合我们的设定
全局服务降级
目前写法的问题:
- 每个业务方法都对应一个兜底方法,而且混在一起写,耦合度高,方法变多
- 希望有自定义的兜底方法,也希望有公用的统一的兜底方法
默认服务降级方法
直接在
客户端80
Controller 上加全局默认兜底注解
@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)/