SpringCloud Alibaba microservice combat 20-integrated Feign downgrade circuit breaker

In the previous project, we have implemented the use of Feign to call the remote interface. This chapter mainly uses sentinel to implement the Feign interface fuse function.

Overview

First, let's look at the effect of calling an unstarted service without using the fuse, and then look at the effect of using the sentinel fuse.

As above, we use the order-service in FeignControlleraccount-service interface in the call, when the fuse is not enabled, the interface will throw an exception 500.

achieve

Using sentinel to realize the fuse is very simple, just a few simple steps.

  1. Define the fallback class and return the default data when the circuit breaks

package com.javadaily.feign.fallback;
@Slf4j
public class AccountFeignFallback implements AccountFeign {
    @Setter
    private Throwable cause;

    @Override
    public ResultData<String> insert(AccountDTO accountDTO) {
        return ResultData.fail("接口熔断");
    }

    @Override
    public ResultData<String> delete(String accountCode) {
        return ResultData.fail("接口熔断");
    }

    @Override
    public ResultData<String> update(AccountDTO accountDTO) {
        return ResultData.fail("接口熔断");
    }

    @Override
    public ResultData<AccountDTO> getByCode(String accountCode) {
        log.error("查询失败,接口异常" ,cause);
        AccountDTO account = new AccountDTO();
        account.setAccountCode("000");
        account.setAccountName("测试Feign");
        return ResultData.success(account);
    }

    @Override
    public ResultData<String> reduce(String accountCode, BigDecimal amount) {
        return ResultData.fail("接口熔断");
    }
}
  1. Write FallbackFactory

@Component
public class AccountFeignFallbackFactory implements FallbackFactory<AccountFeign> {
    @Override
    public AccountFeign create(Throwable throwable) {
        AccountFeignFallback accountFeignFallback = new AccountFeignFallback();
        accountFeignFallback.setCause(throwable);
        return accountFeignFallback;
    }
}
  1. Assign a fuse factory to the feign interface

@FeignClient(name = "account-service",fallbackFactory = AccountFeignFallbackFactory.class)
public interface AccountFeign {
    ...
}
  1. Turn on the circuit breaker in the consumption profile

feign:
  sentinel:
    enabled: true

After the above four steps, we can realize the fuse of the interface, and then restart the order-service to verify the result. The system can't start normally! ! !

The stack information is as follows:

2020-10-23 15:22:14,286 ERROR SpringApplication:826 - Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'feignController': Unsatisfied dependency expressed through field 'accountFeign'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.javadaily.feign.account.AccountFeign': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: No fallbackFactory instance of type class com.javadaily.feign.factory.AccountFeignFallbackFactory found for feign client account-service
 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
 at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]

problem solved

As the saying goes, "Problems are not terrible. The terrible thing is that we are afraid of problems." Looking at the startup log above, it should be impossible to find AccountFeignFallbackFactory. Next, let's look at the source code of FeignClient:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {
 ...省略部分代码,保留关键代码...

 /**
  * Fallback class for the specified Feign client interface. The fallback class must
  * implement the interface annotated by this annotation and be a valid spring bean.
  * @return fallback class for the specified Feign client interface
  */
 Class<?> fallback() default void.class;
 ...省略部分代码,保留关键代码...
}

Pay attention to the comments, it is said that Feign's downgraded class must implement the Feign interface and must be a Spring Bean.

The reason for the error should be "The downgraded class is not registered as Spring Bean."

Everyone knows that when SpringBoot starts, the package and subpackages where the main startup class is located are scanned by default for Bean instantiation.

Order-service items located in the master boot type com.javadaily.order, then only the scan order-service to the start of the project com.javadaily.orderand com.javadaily.orderof sub-packets, the degraded class AccountFeignClient AccountFeignFallbackpackage path is com.javadaily.feign.fallbacksuch that it can not be instantiated Spring, eventually leading to project start failure.

Now that the cause of the problem is located, it is easy to solve, as long as the package path of the Feign downgrade class is configured on the startup class.

@SpringBootApplication(scanBasePackages = {"com.javadaily.feign"})

After adding this configuration, the system can start normally, but the calling interface returns the following error:

{
  "timestamp": "2020-10-27T03:30:44.664+0000",
  "status": 401,
  "error": "Unauthorized",
  "message": "Unauthorized",
  "path": "/order/getAccount/jianzh5"
}

The reason for this problem is that after we configure the path of the Feign downgrade class through scanBasePackages, our own Bean cannot be instantiated, so we also need to configure the scan path of our own project, namely:

@SpringBootApplication(scanBasePackages = {"com.javadaily.feign","com.javadaily.order"})

So far all problems are solved, we access the interface again, and return to our default results when the system fails.

summary

In this chapter, we add a fuse to the Feign interface, and the system will return the default data when the instance fails. In this way, when a certain service is unavailable, its consumers will wait for a long time, and the thread pool will be exhausted, which will affect the thread calls of other services. This is also commonly referred to as the "avalanche effect".

Of course, there was a little setback in the implementation process. The summary is "If your Feign client is written by the consumer, this problem will not occur in the consumer's own module. If it is written and provided by the producer, you need to pay attention Spring Bean instantiated scan path, if you can not scan instantiated class fuse, just in the startup class by scanBasePackagesscanning the path to the corresponding 」 .


Here is a small gift for everyone, follow the official account, enter the following code, you can get the Baidu network disk address, no routines!

001: "A must-read book for programmers"
002: "Building back-end service architecture and operation and maintenance architecture for small and medium-sized Internet companies from scratch"
003: "High Concurrency Solutions for Internet Enterprises"
004: "Internet Architecture Teaching Video"
006: " SpringBoot Realization of
Ordering System" 007: "SpringSecurity actual combat video"
008: "Hadoop actual combat teaching video"
009: "Tencent 2019 Techo Developer Conference PPT"

010: WeChat exchange group

 

 

Guess you like

Origin blog.csdn.net/jianzhang11/article/details/109349106