4 fuse Spring Cloud Hystrix

Posted by cedtech23 on Fri, 28 Jan 2022 19:24:22 +0100

catalogue

1 Introduction

2 fuse principle

2.1 three states of fuse

2.2 conditions for fusing

3. Fuse case

4 service degradation method

1 Introduction

Background, why fuse:

  • In microservices, a request may require multiple microservice interfaces to be implemented, which will form a complex call link.
  • If a service has an exception, the request is blocked, the user cannot get a response, and the threads in the container will not be released. Therefore, more and more user requests are piled up and more threads are blocked.
  • A single server supports a limited number of threads and concurrency. If requests are blocked all the time, it will lead to the depletion of server resources, resulting in the unavailability of all other services, resulting in an avalanche effect.
  • The main methods used by Hystrix to solve the avalanche problem are service degradation and thread isolation. The following content only talks about service degradation.

Overview of Hystrix functions:

  • Protect and control delays and failures of dependencies accessed through third-party client libraries, usually through the network
  • Preventing avalanche effects in complex distributed systems
  • Step back and downgrade as gracefully as possible
  • Fast failure, fast recovery

2 fuse principle

Fuse is a big concept. Generally speaking, when the load exceeds a certain limit, the fuse will trigger the protection mechanism of the system.
Service degradation is the specific manifestation of fuse protection mechanism.

  • Q: service A depends on service B, but B cannot provide services normally. What should I do?
  • A: set a method of service degradation on service A. once service B fails to provide services to service a normally, service a will not be involved because of the problems of service B. therefore, service a will continue to provide services by adopting a minimum degradation strategy. Although the service a at this time is not what the user really wants, it is always better than a pile of exception reminders on the display interface or involving subsequent services.

2.1 three states of fuse

  • Off status, all requests for normal access
  • Open status, all requests will be degraded.

Hystrix will count the request conditions. When the percentage of failed requests reaches the threshold for a certain time, it will trigger the fuse and the circuit breaker will be completely closed
The default threshold of failure ratio is 50%, and the minimum number of requests is no less than 20

  • Half open state

The open state is not permanent. After opening for a while, it will enter the sleep time (5 seconds by default). After the sleep time, it will enter the half open state.
Half open status: the fuse will judge the return status of the next request. If successful, the fuse will switch back to the closed status. If it fails, the fuse switches back to the open state.

2.2 conditions for fusing

First of all, I think "fusing" and "degradation" are similar concepts, just like catching and handling exceptions.

  • 1 access timeout
  • 2 service unavailable (dead)
  • 3. The service throws an exception (although there is an exception, it is still alive)
  • In addition: the request leads to service exceptions. After reaching the threshold, all services will be involved and degraded

3. Fuse case

Based on the above four situations, suppose that service consumer A depends on service provider B (or even other services), and now B makes an error. Let's see what happens when accessing service A.

Implementation steps

  • starter dependent coordinates introduced
  • Open fuse annotation @ enablercircuitbreaker
  • Write the method of service degradation processing
  • Configure policy
  • Analog exception code
  • Test the effect of fuse service
<!--Fuse Hystrix starter-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
//Simplified annotation: in microservices, multiple annotations are often introduced, and composite annotations can be used for simplified annotations@ SpringCloudApplication 
// Equivalent to @ springbootapplication + @ enablediscoveryclient + @ enablercircuitbreaker
@SpringCloudApplication
public class ConsumerServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerServiceApplication.class, args);
    }
    /**
     * Let consumers support load balancing: just add a @ LoadBalanced annotation to the RestTemplate injection method!
     */
    @Bean //Equivalent to ApplicationContext bean tags in XML
    @LoadBalanced //Enable the restTemplate object to support load balancing
    //Once enabled, the traditional url address is requested http://127.0.0.1:9091/user/findById?id=1 It won't work
    // Instead, use the load balancing address: http://user-service/user/findById?id=1
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
/**
     *  Write the service degradation processing method: use @ HystrixCommand to define the fallback method
     */
    @RequestMapping("/hystrix_ribbon_consumer/{id}")
    @HystrixCommand(fallbackMethod ="queryByIdFallback")
    //Parameter fallbackMethod: sets the degradation method of this method. defaultFallback: sets the global service degradation method
    public User HystrixRibbonFindById(@PathVariable("id") Integer id){
        //Load balancing accesses the service. At this time, the host and port parts of the access address become the name of the accessed service
        //Note: once the restTemplate uses load balancing, the traditional url access cannot be used! In other words, the above method findById is no longer applicable
        //Because the current practice is to select the appropriate service through the service name and combined with the load balancer,
        // If you still use url access, you will use "host+port" as the service name to find the corresponding service cluster in eureka. Of course, you can't find it!
        String url = "http://user-service/user/findById?id="+id;
        User user = restTemplate.getForObject(url, User.class);
        return user;
    }

    /**
     *  Service degradation method: the parameters and return value of this method must be consistent with the degraded method!
     */
    public User queryByIdFallback(Integer id){
        User user = new User();
        user.setUsername("Network congestion, please try again later");
        return user;
    }

Configure the fusing strategy in service A as follows:

# Configure fusing strategy:
# There are three situations that trigger the fuse: 1. The service is unavailable; 2. The request times out; 3. Throw an exception
# The fuse function is forced on, and the default is false
hystrix.command.default.circuitBreaker.forceOpen: false
# Trigger fusing error proportional threshold, default 50%
hystrix.command.default.circuitBreaker.errorThresholdPercentage: 20
# Sleep duration after fusing, default value: 5S (unit: ms)
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds: 20000
# The minimum number of fuse trigger requests. The default value is 20
hystrix.command.default.circuitBreaker.requestVolumeThreshold: 5
# Fuse timeout setting, the default is 1 second
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 2000

So far, the basic conditions have been set up. Next, test the four exceptions mentioned in 2.2:

  • 1 access timeout
  • 2 service unavailable (dead)
  • 3. The service throws an exception (although there is an exception, it is still alive)
  • In addition: the request leads to service exceptions. After reaching the threshold, all services will be involved and degraded

(1) Access timeout

Set a 3-second delay in the service provider's method, but in the fuse configuration of Hystrix, it is required to fuse after more than 2 seconds. It is found that the service is indeed degraded (blown).

(2) Service Unavailable

Since Ribbon load balancing is still on, there are three instances of service providers. If only one service is stopped, it is not easy to make the service unavailable. Simply stop all three instances of service providers. It is found that the service is indeed degraded.

(3) The service threw an exception

Modify the code of the service provider: if the request parameter is 1, an exception will be thrown directly; otherwise, no exception will be thrown. On the one hand, this modification method tests whether the service provider will enter the circuit breaker when it throws an exception to the consumer. On the other hand, it can be used to test whether the opening of the starting fuse will affect the normal access of other services when multiple requests fail (if the request parameter is not 1).

At this time, when the access parameter is 2, it can still be accessed normally (), but when the parameter is 1, degradation is triggered.

After accessing the address with the request parameter of 1 for many times, because the service request exception rate reaches the threshold, even the service with the request parameter of 2 (analogy only) cannot be accessed normally, so the fourth case is verified!

4 service degradation method

Note: the fuse service degradation method must ensure the same parameter list and return value as the degraded method.

Service degradation can be written in two ways:

  • fallback method for service degradation on method (this local degradation method is used in Section 3)

Use the HystrixCommon annotation to define
@HystrixCommand(fallbackMethod="queryByIdFallBack") is used to declare a fallback method of degraded logic

  • fallback method of default service degradation on class (Global degradation method)

Put @ DefaultProperties(defaultFallback = "defaultFallBackMethod") on the class instead of the method
Note: if the global service degradation strategy is used, no parameters can be added after @ HystrixCommand, but the annotation must be added!

Topics: Java Spring Cloud