Principle and usage analysis of spring cloud circuit breaker hystrix

Time:2020-6-25

This article mainly introduces the principle and usage analysis of the spring cloud circuit breaker hystrix. The example code is introduced in detail in this article, which has certain reference learning value for your study or work. You can refer to the following for your friends

In a distributed environment, some of the many service dependencies are bound to fail. Hystrix is a library that helps you control the interaction between these distributed services by adding delay tolerance and fault tolerance logic. Hystrix does this by isolating access points between services, stopping cascading failures, and providing fallback options, all of which improve the overall resilience of the system

Two important classes

  • HystrixCommand
  • HystrixObservableCommand

The degradation policy can be added in the annotation @ hystrixcommand (fallbackmethods = “methods”) methods

In addition to service degradation

Request caching is also provided

  • @CacheResult
  • @CacheRemve

But when adding cacheresult, say

Hystrixrequestcontext is not initialized.


2020-01-13 16:12:10.273 ERROR 15348 --- [nio-8083-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]  : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.reflect.UndeclaredThrowableException] with root cause

java.lang.IllegalStateException: Request caching is not available. Maybe you need to initialize the HystrixRequestContext?
  at com.netflix.hystrix.HystrixRequestCache.get(HystrixRequestCache.java:104) ~[hystrix-core-1.5.18.jar:1.5.18]
  at com.netflix.hystrix.AbstractCommand$7.call(AbstractCommand.java:478) ~[hystrix-core-1.5.18.jar:1.5.18]
  at com.netflix.hystrix.AbstractCommand$7.call(AbstractCommand.java:454) ~[hystrix-core-1.5.18.jar:1.5.18]
  at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46) ~[rxjava-1.3.8.jar:1.3.8]
  at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35) ~[rxjava-1.3.8.jar:1.3.8]

View official documents https://github.com/Netflix/Hystrix/wiki/How-To-Use

Typically this context will be initialized and shut down via a ServletFilter that wraps a user request or some other lifecycle hook.

In the context of the same user request, the return data of the same dependent service is always consistent. If the same dependency is called repeatedly in the current request, it will only be called once. The data can be consistent in the current request.

Initialization is done in filter (official recommendation), but every request will be initialized. Therefore, it can solve the problem of high concurrency and ensure the thread safety of resources. Useful in some scenarios.

Request merge

/**
   *Recommendation: service provider has a high delay. Consider using request merging
   *When the hystrixcollapser merges requests, a request handler is created. If the number of requests for each merge is small, and only a few requests need to be merged, the merge time window will be created
   *With the increase of concurrency, the creation and consumption of time window increase. Therefore, only in the time window, there is a large amount of concurrency. It is recommended to merge requests.
   *
   *Batchmethod request replacement method after merging com.gitee.munan56 . cloud.hystrixconsumer.AService#findALl ( java.util.List )Note that the client should have this method
   *Hystrixproperty a property merge time window 100s after this time, a request will be initiated, that is to say, this time is the merge processing time
   * @param id
   * @return
   */
  @HystrixCollapser(batchMethod = "findALl",collapserProperties = @HystrixProperty(name = "timerDelayInMilliseconds",value = "100"))
  public String doBFindOne(String id){

    System.out.println("begin do provider service");
    return restTemplate.getForEntity("http://service-provider:8081/api/v1/provider/do",String.class).getBody();
  }

All codes

package com.gitee.munan56.cloud.hystrixconsumer;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import com.netflix.ribbon.proxy.annotation.Hystrix;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * @author munan
 * @version 1.0
 * @date 2020/1/13 10:41
 */
@Service
public class AService {

  @Autowired
  private RestTemplate restTemplate;

  public String doAService(){
    return "A Service is run";
  }

//  @Hystrix(fallbackHandler = )
  @HystrixCommand(fallbackMethod = "error")
  public String doBServiceOne(){
    System.out.println("begin do provider service");
    return restTemplate.getForEntity("http://service-provider:8081/api/v1/provider/do",String.class).getBody();
  }

  /**
   *Cacheresult request cache (for the request cache), it is officially recommended to initialize the hystrixrequestcontext in the serverlet filter
   *In the context of the same user request, it is valid in the context of unified request.
   * @param id
   * @return
   */
  @CacheResult(cacheKeyMethod = "getKey")
  @HystrixCommand(fallbackMethod = "error")
  public String doBServiceTwo(String id){

    System.out.println("begin do provider service");
    return restTemplate.getForEntity("http://service-provider:8081/api/v1/provider/do",String.class).getBody();
  }

  /**
   *Recommendation: service provider has a high delay. Consider using request merging
   *When the hystrixcollapser merges requests, a request handler is created. If the number of requests for each merge is small, and only a few requests need to be merged, the merge time window will be created
   *With the increase of concurrency, the creation and consumption of time window increase. Therefore, only in the time window, there is a large amount of concurrency. It is recommended to merge requests.
   *
   *Batchmethod request replacement method after merging com.gitee.munan56 . cloud.hystrixconsumer.AService#findALl ( java.util.List )Note that the client should have this method
   *Hystrixproperty a property merge time window 100s after this time, a request will be initiated, that is to say, this time is the merge processing time
   * @param id
   * @return
   */
  @HystrixCollapser(batchMethod = "findALl",collapserProperties = @HystrixProperty(name = "timerDelayInMilliseconds",value = "100"))
  public String doBFindOne(String id){

    System.out.println("begin do provider service");
    return restTemplate.getForEntity("http://service-provider:8081/api/v1/provider/do",String.class).getBody();
  }

  @HystrixCommand()
  public String findALl(List<String> ids){
    System.out.println("begin do provider service");
    return restTemplate.getForEntity("http://service-provider:8081/api/v1/provider/do",String.class).getBody();
  }

  /**
   *Service degradation
   *Specifies the callback method that invokes the service in error
   * @return
   */
  public String error(Throwable e){
    return "do provider error this is default result" + "the error is " + e.getMessage();
  }
  /**
   *Service degradation
   *Specifies the callback method that invokes the service in error
   * @return
   */
  public String error(String id ,Throwable e){
    return "do provider error this is default result" + "the error is " + e.getMessage();
  }


  public String getKey(String id){
    return id;
  }
}

The above is the whole content of this article. I hope it will help you in your study, and I hope you can support developepaer more.