Using Hystrix to implement circuit breakers in Spring Cloud

1. Why use Hystrix

When calling between multiple microservices, assume that microservice A calls microservice B and microservice C, and microservice B and microservice C are calling other microservices. This is the so-called “fan-out”. If the call response time of a certain microservice on the fan-out link is too long or is unavailable, the call to microservice A will occupy more and more system resources, causing the system to crash. This is the so-called “< strong>Avalanche Effect”.

2. Overview of Hystrix

The occurrence of this “avalanche effect” is definitely terrible. In a distributed system, we cannot guarantee that a certain service will not have problems, and Hystrix can solve it.

Hystrix is an open source library used to handle latency and fault tolerance in distributed systems. In distributed systems, many services inevitably fail to call, such as timeouts, exceptions, etc. Hystrix can ensure that when a service fails, It will not cause the failure of the overall service and avoid cascading failures to improve the resilience of the distributed system.

3.Usage of Hystrix

3.1 Use hystrix service breaker in the requested interface class

1. Add dependencies

order-service

 <!-- Introducing hystrix integrated with spring cloud -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>2.2.10.RELEASE</version>
        </dependency>

2. Activate hystrix

@EnableHystrix
public class OrderServiceApplication {<!-- -->

3. Downgrade processing

(1) Add a downgrade method in OrderController

/**
 * Downgrade method
 * The return value and method parameters are consistent with the method that needs to be protected
 */
public Product orderFallBack(Long id){
    Product product = new Product();
    product.setProductName("Trigger downgrade method");
    return product;
}

(2) Use @HystrixCommand configuration on methods that need to be protected

 @HystrixCommand(fallbackMethod = "orderFallBack")
    @GetMapping(value = "/buy/{id}")
    public Product findById(@PathVariable Long id) {
        return productFeignClient.findById(id);

(3) Simulate network delay (in product-service)

 try {
            Thread.sleep(2000l);//Simulate request network delay
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

(4) Hystrix configuration (in application.yml of order-service)

hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: ExecutionIsolationStrategy.SEMAPHORE #Semaphore isolation
          #strategy: # ExecutionIsolationStrategy.THREAD thread pool isolation
          thread:
            timeoutInMilliseconds: 2000 #The default connection timeout is 1 second. If no data is returned within 1 second, the downgrade logic will be automatically triggered.
      circuitBreaker:
        requestVolumeThreshold: 5 #Minimum number of requests to trigger circuit breaker, default 20/10 seconds
        sleepWindowInMilliseconds: 10000 #How many seconds after the fuse is broken to try the request. Default 5 is the time to open the state.
        errorThresholdPercentage: 50 #Minimum proportion of failed requests that trigger circuit breaker, default 50%

(5) Test

Start eureka, product, and order services http://localhost:9002/order/buy/1

Because the simulated network delay is 2s and the database request will be greater than 2s, the downgrade method will be triggered. Now change the thread timeout to 6s and see the results.

Normal access to data

4. Unified downgrade method

If you write a downgrade method for each method, it will be very troublesome when there are many methods. You can specify the downgrade method uniformly.

(1) Modify the OrderController class and add a unified downgrade method

 /**
     * Specify a unified downgrade method
     * Note that the method has no parameters
     */
    public Product defaultFallBack(){
        Product product = new Product();
        product.setProductName("Trigger unified downgrade method");
        return product;
    }

(2) Add the @DefaultProperties annotation above the OrderController class

@DefaultProperties(defaultFallback = "defaultFallBack")
public class OrderController {<!-- -->

(3) Modify the @HystrixCommand annotation above the findById method and change @HystrixCommand(fallbackMethod = “orderFallBack”) to @HystrixCommand

(4) 6s>2s

(5) Test

3.2 Feign combines hystrix service circuit breaker

1. Copy service

Copy order-service to get order-service-feign_hystrix (Note: There will be problems if you copy directly in idea. There will be no problems if you copy it in the file explorer.)

2. Open hystrix and related configurations in feign

Modify order-service-feign_hystrix service application.yml to enable hystrix in Fegin

# Enable hystrix fusing in feign
Feign:
  circuitbreaker:
    enabled: true

Modify port number and service name

server:
  port: 9003
spring:
  application:
    name: service-order-feign_hustrix

hystrix settings

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000 #The default connection timeout is 1 second. If no data is returned within 1 second, the downgrade logic will be automatically triggered.
      circuitBreaker:
        enabled: true
        requestVolumeThreshold: 5
        errorThresholdPercentage: 10
        sleepWindowInMilliseconds: 10000

3. Implement downgrade logic in the interface implementation class

Write the interface implementation class and write the circuit breaker and downgrade method.

package org.example.order.feign;
 
import org.example.order.entity.Product;
import org.springframework.stereotype.Component;
 
@Component
public class ProductFeginClientCallBack implements ProductFeignClient{
    /**
     * Downgrade method
     */
    @Override
    public Product findById(Long id) {
        Product product = new Product();
        product.setProductName("Trigger Feign circuit breaker downgrade method");
        return product;
    }
}

4. Interface annotation declares downgraded class

Modify ProductFeignClient interface

In @FeignClient add the class where the method using fallback is located fallback = ProductFeginClientCallBack.class

@FeignClient(name = "service-product", fallback = ProductFeginClientCallBack.class)
public interface ProductFeignClient {
 
    /**
     * Configure the microservice interface that needs to be called
     * @return
     */
    @RequestMapping(value = "/product/{id}", method = RequestMethod.GET)
    Product findById(@PathVariable("id") Long id);
}

Comment or delete the @EnableHystrix annotation of the startup class

6. Test

Start eureka, product, order (9003) service http://localhost:9003/order/buy/1