[Hystrix Technical Guide] (1) Basic usage and configuration instructions

Many things in this world exist because of belief, so people made clay Bodhisattva with their own hands, but chose to believe in it firmly.

  • The scale and complexity of distributed systems continue to increase, and with it comes higher and higher requirements for the availability of distributed systems. In various high-availability design patterns, [fusing, isolation, degradation, current limiting] are often used. As for related technologies, Hystrix itself is no longer considered a new technology, but it is the most classic technology system! .

  • Hystrix is ​​designed to achieve fuse degradation, thereby improving the availability of the system.

  • Hystrix is ​​a Java service component library that implements circuit breaker mode and compartment mode on the calling side, and improves system fault tolerance by avoiding cascading failures, thereby achieving high availability design.

  • * Hystrix implements resource isolation mechanism

  • Introduce the basic usage and basic configuration of Hystrix

  • * Use Hystrix to realize the basic fuse design to protect the security of the application and realize the preliminary high-availability design.

  • The main purpose of Hystrix is ​​to protect cross-process calls and avoid cascading failures caused by timeouts and other issues.

  • * The implementation method of Hystrix is ​​to encapsulate cross-process calls. There are many specific usage methods: from the programming method, it can be divided into programming method and annotation method; from the calling method, it can be divided into synchronous calling method, asynchronous calling method and reactive calling method.

Let's first look at the most common synchronous programming methods:

code example


public class AuthService {
    
    

  private UserService userService;

  public boolean validateUser(String userId) {
    
    
    User user = new GetUserCommand(userId).execute();
    if (user == null) {
    
    
      return false;
    } else {
    
    
      return user.isValid();
    }
  }

class GetUserCommand extends HystrixCommand {
    
    
    private Long userId;
    public GetUserCommand(Long userId) {
    
    
      super(Setter.withGroupKey(HystrixCommandGroupKey.

      Factory.asKey("UserService"))
          .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
              .withCoreSize(20)
          )
          .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
              .withExecutionTimeoutInMilliseconds(100)
          )
      );
      this.userId = userId;
    }

    public User run() throws Exception {
    
    
      return userService.getUserById(userId);
    }

    public User getFallback() {
    
    
      return new InvalidUser();
    }
  }
}
复制代码

code explanation

  • The common usage of Hystrix is ​​to create an inner class (GetUserCommand in this case) in a business processing class (AuthService in this case) .
  • This inner class needs to extend HystrixCommand. The reason why internal classes are used is that Hystrix is ​​usually used to encapsulate a remote call, usually calling a business method directly .
    • This business method is usually located in a business processing class or a class that this business processing class depends on. The use of inner classes can simplify this call.
  • Extending HystrixCommand also needs to declare a generic type, which represents the return value of the execution method (run, construct, etc.) of this HystrixCommand.
  • Defining a HystrixCommand also requires defining a constructor. This constructor is very important, because when using this HystrixCommand, parameters need to be passed through the constructor. In the constructor, the parent constructor needs to be called to configure the current HystrixCommand. There are three main configurations: GroupKey , ThreadPoolSize and Timeout . There are many specific configuration methods, and one of the more commonly used methods is to configure through a Builder class called Setter.
Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("UserService"))
复制代码
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(20))
复制代码
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(100)
复制代码
  • Implement the business logic in it by implementing the run() method. Usually it is to call a method of an external class or a method that an external class depends on. By implementing the getFallback() method, the failure logic can be implemented, and functions such as degradation can be implemented in it.
  • * After writing GetUserCommand, you need to create a new object every time you use it, and then call the execute() method. Note, do not call the run() method, otherwise functions such as fusing and isolation will not take effect.

basic configuration

The above section introduces the basic usage of HystrixCommand, but only briefly introduces a few configurations. Therefore, the following will give a more detailed introduction to the role of the relevant configuration of HystrixCommand.

The configuration of Hystrix has three dimensions: global default configuration, instance default configuration, and instance dynamic configuration . Except for a few configuration items, most configurations support dynamic modification.

Next, we will introduce the default Instance configuration methods of some main parameters. This configuration method is also the first configuration method that Hystrix comes into contact with.

GroupKey is an indispensable configuration of HystrixCommand, and other configurations are optional. So, using Hystrix you can use the following code:

public class CommandHelloWorld extends HystrixCommand {
    
    
  private final String name;

  public CommandHelloWorld(String name) {
    
    
    super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
    this.name = name;
  }

  protected String run() {
    
    
    return "Hello " + name + "!";
  }
}
复制代码

HystrixCommandGroupKey is an interface. In addition to being defined in the form of HystrixCommandGroupKey.Factory.asKey("ExampleGroup"), this interface can also be implemented directly. For example, use the following method:


public enum Groups implements HystrixCommandGroupKey {
    
    
  GROUP_1
}

class EnumGroupCommand extends HystrixCommand {
    
    

  EnumGroupCommand() {
    
    
    super(Groups.GROUP_1);
  }

  protected String run() throws Exception {
    
    
    LOGGER.info("Thread of Command: {}", Thread.currentThread().getName());
    return null;
  }
}
复制代码

As in the above code, using a custom enumeration class to implement the HystrixCommandGroupKey interface can unify the definition of Hystrix Command Group and simplify configuration.

HystrixCommandGroupKey has two main functions:

  • One is to play the role of group monitoring and alarm. The following articles will introduce monitoring and other aspects;
  • The second is to play the role of group thread pool without configuring HystrixThreadPoolKey. By default, HystrixCommandGroupKey is used to name the thread pool. HystrixCommand that uses the same HystrixCommandGroupKey and does not have a custom HystrixThreadPoolKey will use the same thread pool

Although HystrixCommandGroupKey can play a role in isolating thread pools, it cannot play a role in finely configuring thread pools.

So the thread pool needs to be configured here:

Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("MyService"))
    .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("MyThreadPool"))
    .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
        .withCoreSize(10)
        .withKeepAliveTimeMinutes(1)
        .withMaxQueueSize(-1)
    )
)
复制代码

The value in the andThreadPoolPropertiesDefaults configuration represents the default value.

Next, introduce item by item:

  • andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(“MyThreadPool”)) This is to configure ThreadPoolKey . This configuration is required if you need to configure different ThreadPools under the same GroupKey.
  • withCoreSize(10) is used to configure the thread pool size. Hystrix has some restrictions on the configuration of the thread pool. Here, only the Core Size of the number of threads can be configured, and the Max Size cannot be configured. If not configured, the default value used is 10 .
  • withKeepAliveTimeMinutes(1) is used to configure the keep alive duration when the number of core threads is idle, the default is 1 mins. This configuration generally does not need to be modified .
  • withMaxQueueSize(-1) is used to configure the size of the thread pool task queue, the default value is -1 .
    • When using -1, SynchronousQueue will be used, which means that the queue is actually just an exchange, and the task will be directly handed over to the worker thread for processing. If there are not enough worker threads, then the task will be rejected; * If any positive integer is used, LinkedBlockingQueue will be used.

The command executes directly related configurations, including isolation policies, timeouts, and Fallback related configurations.

Next, introduce several main configurations:

The default isolation strategy is to implement thread pool isolation, and another isolation strategy is Semaphore. Instance default configuration can be set using the following methods:

HystrixCommandProperties.Setter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)
复制代码

This configuration is usually not configured

The default time is 1000ms, and the unit is milliseconds .

Instance default configuration can be set using the following methods :

.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(100))
复制代码

This configuration is more important, and how to adjust this parameter will be introduced in detail later.

In the default configuration of Instance, it is set by the following code:

super(Setter.withGroupKey(BASIC_USAGE_GROUP)
    .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
        .withFallbackIsolationSemaphoreMaxConcurrentRequests(10)
    )
);
复制代码
  • The default value is 10. Because the getFallback() method is executed using the same thread pool as the run() method, too high concurrency will affect the execution of the main logic, so it is necessary to control the amount of concurrency.
  • * If getFallback() executes quickly, then you don't need to modify this value. If you perform a time-consuming operation in getFallback(), you need to consider modifying this value.

share resources

Information sharing
To obtain the above resources, please visit the open source project and click to jump

Guess you like

Origin blog.csdn.net/star20100906/article/details/132155478