一、场景
服务间相互调用时,分为服务调用方与服务提供方两个角色。今天我们所解决的问题就是在服务提供方发生超时或者异常(比如 400、500 Error Code)的时候,自动执行的一段业务逻辑,比如执行一段兜底逻辑将服务请求从失败状态中恢复,如何友好的将错误信息返回给调用方,如何将错误信息log输出,方便定位问题。二、定义与分析
OpenFeign 对服务降级的支持是借助 Hystrix 组件实现的。 OpenFeign 支持两种不同的方式来指定降级逻辑,一种是定义 fallback 类,另一种是定义 fallback 工厂。这个的区别在于如果你想要在降级方法中获取到异常的具体原因,那么你就要借助 fallback 工厂的方式来指定降级逻辑了。 异常传递? 在找解决方案过程中要有demo 正常情况下当被调用服务返回response的status不等于200,就会进入到feign.codec.ErrorDecoder#decode方法中,这里会抛出一个RetryableException异常,自动进入fallback 而我们的系统都会把异常封装为200 首先对inner方法出现异常情况进行特殊处理,不再走全局gloable而是返回应该有的httpStatus状态三、解决方案
轻量级方案: 1、服务提供方 (1)由于 Hystrix 已经从 Spring Cloud 组件库中被移除,所以我们需要在 pom 文件中手动添加 hystrix 项目的依赖。<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.10.RELEASE</version> <exclusions> <!-- 移除Ribbon负载均衡器,避免冲突 --> <exclusion> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-ribbon</artifactId> </exclusion> </exclusions> </dependency>
(2)定义降级为开启状态: (3)抽象工厂 create 方法的入参是一个 Throwable 对象。这样一来,我们在降级方法中就可以获取到原始请求的具体报错异常信息了。
@FeignClient(value = "coupon-template-serv", path = "/template", // 通过抽象工厂来定义降级逻辑 fallbackFactory = TemplateServiceFallbackFactory.class) public interface TemplateService { // ... 省略方法定义 }
@Slf4j @Component public class TemplateServiceFallbackFactory implements FallbackFactory<TemplateService> { @Override public TemplateService create(Throwable cause) { // 使用这种方法你可以捕捉到具体的异常cause return new TemplateService() { @Override public CouponTemplateInfo getTemplate(Long id) { log.info("fallback factory method test"); return null; } @Override public Map<Long, CouponTemplateInfo> getTemplateInBatch(Collection<Long> ids) { log.info("fallback factory method test"); return Maps.newHashMap(); } }; } }2、服务调用方 (1)要指定降级服务所在位置@Component加载范围 在SpringBootApplication注解内有ComponentScan注解可以设定加载范围 重量级方案: 通过 Spring Cloud Alibaba 的组件 Sentinel 搭建中心化的服务容错控制逻辑,这是一种重量级的服务容错手段。 我们做技术选型的时候也要考虑开发成本和维护成本。 比如像 Sentinel 这类中心化的服务容错控制台,它的功能固然强大,各种花式玩法它都考虑到了。但相对应地,如果在项目中引入 Sentinel,在运维层面你要多维护一个 Sentinel 服务集群,并且在代码中接入 Sentinel 也是一个成本项。如果只需要一些简单的降级功能,那 OpenFeign+Hystrix 的 Client 端降级方案就完全可以满足要求,我认为没必要拿大炮打苍蝇,过于追求一步到位的高大上方案。