spring cloud microservice architecture (4): fuse and isolation mechanism for the use of Hystrix

The circuit breaker mechanism mentioned in the second article is one of the ways Hystrix solves the "avalanche". The content of this article:

  1. The basic principle of fuse
  2. Implementation and use of fuses by Hystrix

1 Turn on the fuse

The fuse is corresponding to the command in the previous article (each command corresponds to a fuse, which is the smallest unit of fuse, I don't know if this is the right understanding...), and the fuse is also used on the client side.

The opening of the fuse of a command needs to meet the following two conditions (by default):

  1. The command exceeds 20 requests in 10 seconds
  2. When the first condition is met, if the requested error percentage is greater than 50%, turn on the fuse

The following is proved by experiments.

Create a spring boot project with the following pom dependencies:

<dependencies>
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-core</artifactId>
            <version>1.5.12</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <version>1.7.25</version>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.2</version>
        </dependency>
    </dependencies>

Let's create a command to call the service. In this command, the timeout time is set to 500ms, and a timeout flag isTimeout is set. Use this flag to control whether the execution of the command times out, as follows:

static class TestCommand extends HystrixCommand<String> {

        private boolean isTimeout;

        public TestCommand(boolean isTimeout) {
            super(Setter.withGroupKey(
                    HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
                    .andCommandPropertiesDefaults(
                            HystrixCommandProperties.Setter()
                                    .withExecutionTimeoutInMilliseconds(500)));
            this.isTimeout = isTimeout;
        }

        @Override
        protected String run() throws Exception {
            if(isTimeout) {
                Thread.sleep(800);
            } else {
                Thread.sleep(200);
            }           
            return "";
        }

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

The 20 times for the first condition can be changed to 3 times through the netflix.config.ConfigurationManager configuration class, which is easier to test. Then the same command is called 10 times (and within 10 seconds)

public static void main(String[] args) throws Exception {
        // 10秒内大于3次请求,满足第一个条件
        ConfigurationManager
                .getConfigInstance()
                .setProperty(
                        "hystrix.command.default.circuitBreaker.requestVolumeThreshold",
                        3);
        boolean isTimeout = true;
        for(int i = 0; i < 10; i++) {
            TestCommand c = new TestCommand(isTimeout);
            c.execute();
            HealthCounts hc = c.getMetrics().getHealthCounts();
            System.out.println("断路器状态:" + c.isCircuitBreakerOpen() + ", 
            请求数量:" + hc.getTotalRequests());
            //if(c.isCircuitBreakerOpen()) {
                //isTimeout = false;
                //System.out.println("============  断路器打开了,等待休眠期结束");
                //Thread.sleep(6000);
            //}
        }
    }

Let's take a look at the result of the execution. The number of requests within 10 seconds satisfies the first condition 3 times; if all 3 times fail, the fuse is turned on.

断路器状态:false, 请求数量:0
断路器状态:false, 请求数量:1
断路器状态:false, 请求数量:2
断路器状态:true, 请求数量:3
断路器状态:true, 请求数量:3
断路器状态:true, 请求数量:3
断路器状态:true, 请求数量:3
断路器状态:true, 请求数量:3
断路器状态:true, 请求数量:3
断路器状态:true, 请求数量:3

2 Closing the fuse

After the fuse of the command is turned on, the command will have a sleep time of 5 seconds by default. During this time, the subsequent request directly executes the fallback method; after 5 seconds, it will try to execute the command once, and if successful, turn off the fuse fuse; otherwise, the fuse remains open.

The commented out code is let go,

if(c.isCircuitBreakerOpen()) {
    isTimeout = false;
    System.out.println("============  断路器打开了,
    等待休眠期结束");
    Thread.sleep(6000);
}

View the execution result:

断路器状态:false, 请求数量:0
断路器状态:false, 请求数量:1
断路器状态:false, 请求数量:2
断路器状态:true, 请求数量:3
============  断路器打开了,等待休眠期结束
断路器状态:false, 请求数量:0
断路器状态:false, 请求数量:0
断路器状态:false, 请求数量:0
断路器状态:false, 请求数量:3
断路器状态:false, 请求数量:3
断路器状态:false, 请求数量:5

After the circuit breaker is closed, the number of requests feels a bit problematic, still need to understand?

3 Thread pool isolation

In the process executed by Hystrix, in addition to going through the circuit breaker, there is also a need to pass: whether the thread pool or semaphore that executes the command is fully loaded. If it is fully loaded, the command will not be executed, and the fallback logic will be launched directly.

The smallest unit targeted by the thread pool is also a command

Create a spring boot project, the content of the pom file is the same as the previous article. First create the command we call the service:

public class MyCommand extends HystrixCommand<String> {

    private int index;

    public MyCommand(int index) {
        super(Setter.withGroupKey(
        HystrixCommandGroupKey.Factory
        .asKey("TestGroupKey")));
        this.index = index;
    }

    @Override
    protected String run() throws Exception {
        Thread.sleep(500);
        System.out.println("执行方法,当前索引:" 
        + index);
        return "";
    }

    @Override
    protected String getFallback() {
        + index);
        return "";
    }
}

First, change the number of concurrent threads to 4, and then execute the command asynchronously through the queue method. The command was executed successfully 4 times, and the fallback method was executed 2 times.

public class ThreadMain {

    public static void main(String[] args) throws Exception {
        ConfigurationManager.getConfigInstance().
        setProperty(default.coreSize, 4);
        for(int i = 0; i < 6; i++) {
            MyCommand c = new MyCommand(i);
            c.queue();
        }
        Thread.sleep(5000);
    }

}
执行回退,当前索引:4
执行回退,当前索引:5
执行方法,当前索引:2
执行方法,当前索引:0
执行方法,当前索引:1
执行方法,当前索引:3

4 Semaphore isolation

Hystrix is ​​thread pool isolation by default. Semaphore isolation is the number of concurrent executions of each command. When the number of concurrent executions is higher than the threshold, no more commands will be executed.

public class SemaphoreMain {

    public static void main(String[] args) throws Exception {
        ConfigurationManager
        .getConfigInstance().setProperty(
                "hystrix.command.default.
                execution.isolation.strategy", ExecutionIsolationStrategy.SEMAPHORE);
.getConfigInstance().setProperty(
                "hystrix.command.default
                .execution.isolation.semaphore.maxConcurrentRequests", 3);
        for(int i = 0; i < 6; i++) {
            final int index = i;
            Thread t = new Thread() {
                public void run() {
                    MyCommand c = new MyCommand(index);
                    c.execute();
                }
            };
            t.start();
        }
        Thread.sleep(5000);
    }

}
执行回退,当前索引:3
执行回退,当前索引:5
执行回退,当前索引:0
执行方法,当前索引:2
执行方法,当前索引:4
执行方法,当前索引:1

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325990385&siteId=291194637