微服务系统中为了防止服务雪崩问题,服务之间相互调用的时候一般需要开启熔断与降级,下面就来看下feign如何集成hystrix来做熔断与降级。
依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--高版本才需要单独引入-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId><version>2.2.10.RELEASE</version>
</dependency>
需要说明的是,低版本的feign默认已经依赖了hystrix,不需要添加额外的依赖,但是高版本的feign默认并没有依赖hystrix,因此需要额外导入hystrix的依赖。
降级
所谓的降级就是在服务之间相互调用的时候,如果提供者抛出了异常,消费者并不会同步的也抛出异常,而是给客户端返回一个降级以后的结果,我们可以给FeignClient添加fallbackFactory来指定降级以后的处理逻辑。
1)让feign开启降级
feign:hystrix:enabled: true
2)给FeingClient添加fallbackFactory
比如我们有一个UserClient:
@FeignClient(value = "userservice",url = "http://localhost:8081",fallbackFactory = UserFallbackFactory.class,configuration = FeignConfig.class)
public interface UserClient {@GetMapping("/user/{id}")public User queryById(@PathVariable("id") Long id);
}
3)实现UserFallbackFactory自定义降级逻辑
public class UserFallbackFactory implements FallbackFactory<UserClient> {@Overridepublic UserClient create(Throwable cause) {return new UserClient(){@Overridepublic User queryById(Long id) {return new User(0L, "fallback user", "fallback address");}};}
}
4)UserFallbackFactory配置到FeignConfig中
UserClient会引用这个配置,从而找到UserFallbackFactory这个bean。
public class FeignConfig {@Beanpublic UserFallbackFactory userFallbackFactory(){return new UserFallbackFactory();}
}
测试一下
如果userservice接口异常,浏览器并不会抛出异常,而是返回将降级以后的结果:
熔断
所谓的熔断就是说假如服务提供者现在已经异常了,消费者就没有必要继续去调用了,反正调用也是失败,干错直接走降级逻辑。那么,hystrix是如何来判断应该是直接走降级逻辑还是应该发起远程调用?这里边主要有以下几个参数:
配置
hystrix:command:default:metrics:rollingStats:timeInMilliseconds: 5000circuitBreaker:requestVolumeThreshold: 2errorThresholdPercentage: 50sleepWindowInMilliseconds: 10000
以上几个参数的含义是: 5秒(timeInMilliseconds)以内,请求次数达到2个(requestVolumeThreshold)以上,失败率达到50%(errorThresholdPercentage)以上,则开启熔断10秒(sleepWindowInMilliseconds)。
测试一下
连续访问10次接口,order-service的输出:
2023-09-08 09:32:44.144 INFO 4364 --- [nio-8080-exec-1] com.github.xjs.web.OrderController : OrderController.queryById(), id=1
2023-09-08 09:32:44.806 INFO 4364 --- [nio-8080-exec-2] com.github.xjs.web.OrderController : OrderController.queryById(), id=1
2023-09-08 09:32:45.408 INFO 4364 --- [nio-8080-exec-3] com.github.xjs.web.OrderController : OrderController.queryById(), id=1
2023-09-08 09:32:45.781 INFO 4364 --- [nio-8080-exec-4] com.github.xjs.web.OrderController : OrderController.queryById(), id=1
2023-09-08 09:32:45.981 INFO 4364 --- [nio-8080-exec-5] com.github.xjs.web.OrderController : OrderController.queryById(), id=1
2023-09-08 09:32:46.261 INFO 4364 --- [nio-8080-exec-6] com.github.xjs.web.OrderController : OrderController.queryById(), id=1
2023-09-08 09:32:46.541 INFO 4364 --- [nio-8080-exec-7] com.github.xjs.web.OrderController : OrderController.queryById(), id=1
2023-09-08 09:32:46.792 INFO 4364 --- [nio-8080-exec-8] com.github.xjs.web.OrderController : OrderController.queryById(), id=1
2023-09-08 09:32:47.029 INFO 4364 --- [nio-8080-exec-9] com.github.xjs.web.OrderController : OrderController.queryById(), id=1
2023-09-08 09:32:47.258 INFO 4364 --- [io-8080-exec-10] com.github.xjs.web.OrderController : OrderController.queryById(), id=1
user-service的输出:
2023-09-08 09:32:44.358 ERROR 9788 --- [nio-8081-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: 查询用户异常] with root cause
2023-09-08 09:32:44.812 ERROR 9788 --- [nio-8081-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: 查询用户异常] with root cause
很显然,前面2次调用失败以后,开启了熔断,后面的8个请求都是直接走的降级逻辑,请求并没有到后端的user-service。
熔断器的工作原理
背后的原理就是AOP,hystrix会拦截并统计远程调用的结果,如果达到熔断的条件,就开启熔断,开启熔断以后,请求就不会到后端的微服务了。当然也不能一直熔断,sleepWindowInMilliseconds时间以后,如果再有新的调用,hystrix会放行一个请求到后端的微服务,如果请求还是失败的,则继续保持熔断,走降级逻辑,如果请求是成功的,则关闭熔断,正常调用后端的微服务。
断路器控制熔断和放行是通过状态机来完成的:
完整的源码下载:https://github.com/xjs1919/enumdemo