文章目录
前言
最近在学习springcloudAlibaba的过程中,遇到了不少的问题,刚好有时间,想把自己遇到的问题在此做一个记录,也希望能够让读者从中得到一点提示,避免采坑。本次就SpringCloud中Feign与Sentinel整合实现隔离和熔断降级时遇到的问题做一个记录。
一、隔离和降级?
限流是一种预防措施,虽然限流可以尽量避免因高并发而引起的服务故障,但服务还会因为其它原因而故障。
而要将这些故障控制在一定范围,避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级手段了。
线程隔离:调用者在调用服务提供者时,给每个调用的请求分配独立线程池,出现故障时,最多消耗这个线程池内资源,避免把调用者的所有资源耗尽。
熔断降级:是在调用方这边加入断路器,统计对服务提供者的调用,如果调用的失败比例过高,则熔断该业务,不允许访问该服务的提供者了。
可以看到,不管是线程隔离还是熔断降级,都是对客户端(调用方)的保护。需要在调用方 发起远程调用时做线程隔离、或者服务熔断。
而我们的微服务远程调用都是基于Feign来完成的,因此我们需要将Feign与Sentinel整合,在Feign里面实现线程隔离和服务熔断。
二、整合步骤
1.修改配置,开启sentinel功能
代码如下:
修改消费者服务的application.yml文件,开启Feign的Sentinel功能:
feign:
sentinel:
enabled: true # 开启feign对sentinel的支持
2.编写失败降级逻辑
业务失败后,不能直接报错,而应该返回用户一个友好提示或者默认结果,这个就是失败降级逻辑。
给FeignClient编写失败后的降级逻辑
①方式一:FallbackClass,无法对远程调用的异常做处理
②方式二:FallbackFactory,可以对远程调用的异常做处理,我们选择这种
步骤一:在feing-api项目中定义类,实现FallbackFactory:
代码示例:
@Slf4j//@ComponentpublicclassOrderClientFallbackFactoryimplementsFallbackFactory<OrderClient>{@OverridepublicOrderClientcreate(Throwable throwable){returnnewOrderClient(){@OverridepublicOrdergetOrderMessage(int ID){
log.error("查询订单异常", throwable);returnnewOrder();}};}}
这里需要注意的点,由于对Feign-API做了一个抽取,此类实现了FallbackFactory接口,重写了create方法。
步骤二:在feing-api项目中的DefaultFeignConfiguration类中将OrderClientFallbackFactory注册为一个Bean:
代码示例:
@ConfigurationpublicclassDefaultFeignConfiguration{@BeanpublicLogger.LevellogLevel(){returnLogger.Level.BASIC;}@BeanpublicOrderClientFallbackFactoryorderClientFallbackFactory(){returnnewOrderClientFallbackFactory();}}
这里是通过配置类的方式,将编写的降级逻辑类注入到容器中,注意两个注解:@Configuration、 @Bean。也可以在降级逻辑类上加上@Component注解,两者效果相同,取其中一种即可。
步骤三:在feing-api项目中的OrderClient接口中使用OrderClientFallbackFactory:
@FeignClient(value="orderservice", fallbackFactory=OrderClientFallbackFactory.class)publicinterfaceOrderClient{@GetMapping("/order/orderMessage")OrdergetOrderMessage(@RequestParam("ID")int ID);
注意@FeignClient(value = “orderservice”, fallbackFactory = OrderClientFallbackFactory.class)中的属性使用,使用的是 fallbackFactory。
步骤四:解决以下异常:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'XXX': Unsatisfied dependency expressed through field 'XXXt'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.qst.feign.clients.XXX': Unexpected exception during bean creation; nested exception is java.lang.IllegalStateException: No fallbackFactory instance of type class com.qst.feign.clients.fallback.OrderClientFallbackFactory found for feign client orderservice
java.lang.IllegalStateException: No fallbackFactory instance of type class com.qst.feign.clients.fallback.OrderClientFallbackFactory found for feign client orderservice 是因为Feign接口及其托底函数,需要和启动类平级或为其子包的类,由于feign-api为单独抽取出来的一个模块,因此需要声明扫描对应的接口的包。
消费者服务的启动类代码示例:
@SpringBootApplication@ComponentScan(basePackages={"com.qst.feign","com.qst.ticket"})@EnableFeignClients(clients={OrderClient.class})//开启Feign客户端publicclassTicketDemoApplication{publicstaticvoidmain(String[] args){SpringApplication.run(TicketDemoApplication.class, args);}}
因为@ComponentScan 和@SpringBootApplication注解的包扫描有冲突,@ComponentScan注解包扫描会覆盖掉@SpringBootApplication的包扫描。所以我的例子上需要改成@ComponentScan(basePackages ={“com.qst.feign”,“com.qst.ticket”}) 一个为feign-api的包,另一个为此启动类下的包。
当初出现的问题是只加了对feign-api包的扫描,没有加对此启动类下的包的扫描,导致服务一只出现404的问题,是因为没弄清楚@SpringBootApplication
@ComponentScan,两者的底层原理,学习之路任重而道远啊~
3.重启后,访问一次订单查询业务,然后查看sentinel控制台,可以看到新的簇点链路,然后就可以在sentinel控制台中为所欲为了。
总结
以上就是今天要记录的内容,希望对大家有所帮助。