所有代码都在github上:https://github.com/demonruin/cloud2020/tree/master
服务降级就是指服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示,fallback
哪些情况会触发降级:程序运行异常,超时,服务熔断触发服务降级,线程池/信号量打满也会导致服务降级;
服务降级分为 服务端降级 和 客户端降级,好比一双筷子,你可以夹肉,也可以夹菜,不过一般是用来在客户端降级使用,具体情况具体分析使用。下面分别举例在服务端降级和 客户端降级代码演示。有个前提啊,就是项目中已经加入了Hystrix的包依赖支持,酌情选择添加
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
服务端降级
1、需要使用@HystrixCommand,设置兜底即fallback降级方法,设置拦截异常信息。8001服务正常timeout时间为6s,但是服务降级做了5秒等待限制,超过了就不再等待,进行服务降级,调用fallback方法;
package com.king.springcloud.service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
* created by king on 2020/4/16 3:22 下午
*/
@Service
public class PaymentHystrixService {
/**
* 成功访问
*
* @param id
* @return
*/
public String getOk(Integer id) {
return "线程池:" + Thread.currentThread().getName() + " ID:" + id + "\t 访问成功";
}
/**
* 访问超时
*
* @param id
* @return
* 5000是指5s
*/
@HystrixCommand(fallbackMethod ="paymentFallback_handler",commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "5000")
})
public String getTimeout(Integer id) {
int timeout = 6;
try {
TimeUnit.SECONDS.sleep(timeout);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " ID:" + id + "\t 访问超时,超时时间(秒):" + timeout;
}
public String paymentFallback_handler(Integer id){
return "线程池:" + Thread.currentThread().getName() + " paymentFallback_handler---ID:" + id + "\t ";
}
}
2、主启动类加注解@EnableCircuitBreaker
package com.king.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* created by king on 2020/4/16 3:21 下午
*/
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class,args);
}
}
3、测试结果展示
此时服务端的服务降级就完成代码演示开发了,下面介绍客户端服务降级演示
客户端服务降级
80订单微服务,也可以更好的保护自己,自己也依样画葫芦进行客户端降级保护。
服务降级,客户端去调用服务端,碰上服务端宕机或关闭,本次案例服务降级处理是在客户端80实现完成的,与服务端8001没有关系,只需要为Feign客户端定义的接口添加一个服务降级处理的实现类即可实现解耦;未来我们要面对的异常有:运行时异常比如1/0的异常,超时异常 比如sleep(5),宕机 即服务端服务器宕机等等
1、首先需要配置yml,启动feign的hystrix支持
feign:
hystrix:
#如果处理自身的容错就开启。开启方式与生产端不一样。
enabled: true
2、主启动类加上启用注解@EnableHystrix
package com.king.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* created by king on 2020/4/16 5:39 下午
*/
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrix
public class OrderFeignHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignHystrixMain80.class,args);
}
}
3、在controller接口上加注解,配置fallback降级兜底方法,进行请求超时等情况下的服务降级
package com.king.springcloud.controller;
import com.king.springcloud.service.OrderFeignHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* created by king on 2020/4/16 5:43 下午
*/
@RestController
@Slf4j
public class OrderFeignHystrixController {
@Resource
private OrderFeignHystrixService orderFeignHystrixService;
@GetMapping(value = "/payment/ok/{id}")
public String getOK(@PathVariable("id") Integer id) {
return orderFeignHystrixService.getOk(id);
}
@GetMapping(value = "/payment/timeout/{id}")
@HystrixCommand(fallbackMethod = "fallbackHystrix_handler_order",
commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")})
public String getTimeout(@PathVariable("id") Integer id) {
return orderFeignHystrixService.getTimeout(id);
}
public String fallbackHystrix_handler_order(@PathVariable("id") Integer id){
return "80请求服务失败";
}
}
此处设置的请求超时时间为1500毫秒,而8001提供的服务超时时间是3000毫秒,所以客户端请求会直接请求超时,调用服务降级fallback方法,结果展示
上面是简单的服务降级举例,但是每个业务方法对应一个兜底的fallback方法,会造成代码膨胀。而降级fallback方法和业务代码混乱在一起,所以一般会进行处理,将统一和自定义的进行区分开,或者将fallback方法从业务代码中抽取出来;
统一和自定义分开:
一、在客户端服务降级,统一处理方式
- 在controller上加统一@DefaultProperties(defaultFallback = "globle_fallbackHystrix_handler")注解
- 在接口上统一加 @HystrixCommand注解
- 自定义的降级处理方法,扔参照timeout的接口自定义服务降级处理方法
package com.king.springcloud.controller;
import com.king.springcloud.service.OrderFeignHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* created by king on 2020/4/16 5:43 下午
*/
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "globle_fallbackHystrix_handler")
public class OrderFeignHystrixController {
@Resource
private OrderFeignHystrixService orderFeignHystrixService;
@GetMapping(value = "/payment/ok/{id}")
@HystrixCommand
public String getOK(@PathVariable("id") Integer id) {
return orderFeignHystrixService.getOk(id);
}
@GetMapping(value = "/payment/timeout/{id}")
@HystrixCommand(fallbackMethod = "fallbackHystrix_handler_order",
commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")})
public String getTimeout(@PathVariable("id") Integer id) {
return orderFeignHystrixService.getTimeout(id);
}
public String fallbackHystrix_handler_order(@PathVariable("id") Integer id){
return "80请求服务失败";
}
public String globle_fallbackHystrix_handler(){
return "请求服务失败,返回全局服务降级处理方法";
}
}
二、将降级方法从业务代码中抽取出来,不再糅合的处理方法
- 去掉上述方法中 在controller上加统一@DefaultProperties(defaultFallback = "globle_fallbackHystrix_handler")注解
- 去掉在接口上统一加 @HystrixCommand注解
- 保留 yml中的feign启用hystrix的配置
- 新建FallbackServiceHandler类,实现接口OrderFeignHystrixService,并重写每一个方法,作为兜底fallback服务降级
- 在OrderFeignHystrixService的feign注解配置上,指定兜底fallback服务降级类
package com.king.springcloud.service;
import org.springframework.stereotype.Component;
/**
* created by king on 2020/4/17 1:31 下午
*/
@Component
public class FallbackServiceHandler implements OrderFeignHystrixService {
public String getOk(Integer id) {
return null;
}
public String getTimeout(Integer id) {
return null;
}
}
package com.king.springcloud.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* created by king on 2020/4/16 5:40 下午
*/
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE-HYSTRIX",fallback = FallbackServiceHandler.class)
public interface OrderFeignHystrixService {
@GetMapping(value = "/payment/ok/{id}")
public String getOk(@PathVariable("id") Integer id);
@GetMapping(value = "/payment/timeout/{id}")
public String getTimeout(@PathVariable("id") Integer id);
}
测试结果如下