Getting started with Hystrix

Keywords: Java Spring Cloud Hystrix

one   High concurrency in microservice architecture

In the microservice architecture, we split the business into services one by one, and services can be called each other. Due to network reasons or their own reasons, the service can not guarantee 100% availability of the service. If a single service has a problem, calling the service will cause network delay. At this time, if there is a large number of network influx, task accumulation will be formed, Cause service paralysis. In the SpringBoot program, the built-in tomcat is used as the web server by default. The maximum concurrent requests supported by a single tomcat are limited. If an interface is blocked and the backlog of tasks to be executed is increasing, it is bound to affect the calls of other interfaces.

  1.1 realize service isolation in the form of thread pool

  (1) Configure coordinates

In order to facilitate the implementation of resource isolation in the form of thread pool, the following dependencies need to be introduced  

<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-metrics-event-stream</artifactId>
    <version>1.5.12</version>
</dependency>
<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-javanica</artifactId>
    <version>1.5.12</version>
</dependency>

(2) Configure thread pool

Configure the implementation class of the HystrixCommand interface, and then configure the thread pool in the implementation class

public class OrderCommand extends HystrixCommand<String> {
    private RestTemplate restTemplate;
    private Long id;

    public OrderCommand(RestTemplate restTemplate, Long id) {
        super(setter());
        this.restTemplate = restTemplate;
        this.id = id;
    }

    private static Setter setter() {
        // Service grouping
        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("order_product");
        // Service identification
        HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("product");
        // Thread pool name
        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("order_product_pool");
        /**
         * Thread pool configuration
         * withCoreSize : The thread pool size is 10
         * withKeepAliveTimeMinutes: Thread lifetime 15 seconds
         * withQueueSizeRejectionThreshold :The threshold value of queue waiting is 100. If it exceeds 100, reject is executed
         strategy
         */
        HystrixThreadPoolProperties.Setter threadPoolProperties =HystrixThreadPoolProperties.Setter().withCoreSize(50)
                                                                        .withKeepAliveTimeMinutes(15).withQueueSizeRejectionThreshold(100);
        // Command properties configure Hystrix on timeout
        HystrixCommandProperties.Setter commandProperties =HystrixCommandProperties.Setter()
                .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)// Using thread pool to realize service isolation
                .withExecutionTimeoutEnabled(false);// prohibit
        return HystrixCommand.Setter.withGroupKey(groupKey).andCommandKey(commandKey).andThreadPoolKey(threadPoolKey)
                    .andThreadPoolPropertiesDefaults(threadPoolProperties).andCommandPropertiesDefaults(commandProperties);
    }

    @Override
    protected String run() throws Exception {
        return restTemplate.getForObject("http://shop-serviceproduct/product/" + id, String.class);
    }

    @Override
    protected String getFallback() {
        return "Fuse degradation";
    }
}

(3) Configuration call

Modify the OrderController and use the custom OrderCommand to complete the call

@Autowired
private RestTemplate restTemplate;
@GetMapping("/buy/{id}")
public String order(@PathVariable Long id) throws ExecutionException,InterruptedException, TimeoutException {
    return new OrderCommand(restTemplate,id).execute();
}

two   Services: Hystrix

 

         2.1 core knowledge of service fault tolerance

                 2.1.1 avalanche effect

In microservice architecture, it is very common for A request to call multiple services. For example, when the client accesses service A, service A needs to call service B, and service B needs to call service C. due to network reasons or its own reasons, if service B or service C cannot respond in time, service A will be blocked until service B and Service C respond. At this time, if A large number of requests flow in, the thread resources of the container will be consumed, resulting in service paralysis. Due to the dependence between services, faults will spread and cause chain reactions, which will have disastrous and serious consequences for the whole microservice system, which is the "avalanche" effect of service faults.         

Avalanche is the butterfly effect in the system, which is caused by various reasons, such as unreasonable capacity design, slow response of a method under high concurrency, or resource depletion of a machine. From the source, we can't completely eliminate the occurrence of avalanche source, but the root cause of avalanche comes from the strong dependence between services, so we can evaluate in advance and do a good job in fusing, isolation and current limitation.

                 2.1.2.   Service isolation  

As the name suggests, it means that the system is divided into several service modules according to certain principles, and each module is relatively independent without strong dependence. When a fault occurs, it can isolate the problem and impact within a module without spreading the risk, affecting other modules and affecting the overall system service.

The so-called degradation means that when a service is blown, the server will no longer be called. At this time, the client can prepare a local fallback callback and return a default value. It can also be understood as telling the truth

                 2.1.4. Service current limit

Current limiting can be considered as a kind of service degradation. Current limiting is to limit the input and output flow of the system to achieve the purpose of protecting the system. Generally speaking, the throughput of the system can be measured. In order to ensure the stable operation of the system, once the threshold that needs to be limited is reached, it is necessary to limit the flow and take a few measures to complete the purpose of limiting the flow. For example: postpone resolution, refuse to resolve, or partially refuse to resolve, etc.

         2.2.   Introduction to Hystrix

Hystrix is a delay and fault tolerance library open source by Netflix. It is used to isolate access to remote systems, services or third-party libraries, prevent cascading failures, and improve system availability and fault tolerance. Hystrix achieves latency and fault tolerance through the following points.

  • Wrap request: use HystrixCommand to wrap the calling logic of the dependency. Each command is executed in a separate thread. This uses command mode in design mode.
  • Trip mechanism: when the error rate of a service exceeds a certain threshold, Hystrix can automatically or manually trip and stop requesting the service for a period of time.
  • Resource isolation: Hystrix maintains a small thread pool (or semaphore) for each dependency. If the thread pool is full, the request to the dependency will be rejected immediately instead of queuing, so as to speed up the failure determination.
  • Monitoring: Hystrix can monitor changes in operational indicators and configurations in near real time, such as success, failure, timeout, and rejected requests.
  • Fallback mechanism: execute fallback logic when the request fails, times out, is rejected, or when the circuit breaker is open. The fallback logic is by the developer
  • Provide it yourself, for example, return a default value.
  • Self repair: after the circuit breaker is opened for a period of time, it will automatically enter the "half open" state.

         2.3.   Rest implementation service

(1) Configuration dependency

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

(2) Open fuse

Add @ enablercircuitbreaker annotation in startup class Application to enable fuse support.

@EntityScan("cn.itcast.entity")
@EnableCircuitBreaker //Open the fuse
@SpringBootApplication
//@SpringCloudApplication / / combined annotation
public class OrderApplication {
    //Create RestTemplate object
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

(3)   Configure business logic

It can be seen from the code that a fallback method findProductFallBack is written. This method has the same parameters and return value type as the findProduct method. This method returns a default error message. Use the fallbackMethod property of the annotation @ HystrixCommand to specify that the degradation method triggered by fusing is findProductFallBack.

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private RestTemplate restTemplate;
    //Place an order
    @GetMapping("/product/{id}")
    @HystrixCommand(fallbackMethod = "orderFallBack")
    public Product findProduct(@PathVariable Long id) {
        return restTemplate.getForObject("http://shop-serviceproduct/product/1", Product.class);
    }
    //Degradation method
    public Product orderFallBack(Long id) {
        Product product = new Product();
        product.setId(-1l);
        product.setProductName("Fuse:Trigger degradation method");
        return product;
    }
}

We just wrote fallback on a business method. If there are many such methods, don't we have to write a lot. Therefore, we can add the fallback configuration to the class to realize the default fallback:

@RestController
@RequestMapping("/order")
@DefaultProperties(defaultFallback = "orderFallBack" )
public class OrderController {

Timeout setting

         In the previous case, the request will return an error message after more than 1 second. This is because the default timeout of Hystix is 1. We can modify this value through configuration:

hystrix:
    command:
        default:
            execution:
                isolation:
                    thread:
                        timeoutInMilliseconds: 2000

         2.4.   Feign implementation service

         Spring cloud fegin integrates hystrix for Feign by default, so you don't need to add hystrix after adding Feign dependencies. How to make Feign's circuit breaker mechanism take effect, just follow the following steps:

(1)   Modify application.yml to open hystrix in Fegin

Hystrix has been built in Feign, but it is turned off by default. You need to turn on the support for hystrix in the application.yml of the project

feign:
    hystrix: #Turn on the hystrix fuse in feign
        enabled: true

(2) Configure the implementation class of FeignClient interface

To implement fuse degradation based on Feign, the degradation method needs to be configured in the implementation class of Feign client interface

/**
* Implement the customized ProductFeginClient interface
* Write a method in the interface implementation class
*/
@Component
public class ProductFeginClientCallBack implements ProductFeginClient {
    /**
    * Degradation method
    */
    public Product findById(Long id) {
        Product product = new Product();
        product.setId(-1l);
        product.setProductName("Fuse:Trigger degradation method");
        return product;
    }
}

(3) Modify FeignClient and add hystrix

Add demotion method in @ FeignClient annotation

//Specify the name of the micro service to be called
@FeignClient(name="service-product",fallback =ProductFeginClientCallBack.class)
public interface ProductFeginClient {
    //The requested path of the call
    @RequestMapping(value = "/product/{id}",method = RequestMethod.GET)
    public Product findById(@PathVariable("id") Long id);
}

 

previous page             next page

Posted by adrian28uk on Wed, 22 Sep 2021 23:04:45 -0700