【Hystrix】四种fallback条件 例子

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010900754/article/details/82563466

Hystrix会在以下四种情况下触发fallback函数:

1.任务超过了"withExecutionTimeoutInMilliseconds"定义的超时时间;

2.任务抛出了非HystrixBadRequestException的异常;

3.超过了线程池线程数目;

4.熔断器打开;

下面一一举例。

1.超时

public class HelloCommand extends HystrixCommand<String> {
    protected HelloCommand() {
        super(
                Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("example"))
                        .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(1000))
        );
    }

    @Override
    protected String run() throws Exception {
        Thread.sleep(2000);
        return "hello";
    }

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

main:

public class App 
{
    public static void main( String[] args )
    {
        try {
            System.out.println(new HelloCommand().execute());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.抛异常:

public class HelloCommand extends HystrixCommand<String> {
    protected HelloCommand() {
        super(
                Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("example"))
                        .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(1000))
        );
    }

    @Override
    protected String run() throws Exception {
        throw new NullPointerException();
    }

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

main:

public class App 
{
    public static void main( String[] args )
    {
        try {
            System.out.println(new HelloCommand().execute());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3.超过线程池线程数目

public class HelloCommand extends HystrixCommand<String> {
    protected HelloCommand() {
        super(
                Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("example"))
                        .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(2000))
                        .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(3))
        );
    }

    @Override
    protected String run() throws Exception {
        Thread.sleep(1000);
        return "hello";
    }

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

main: 

public class App 
{
    public static void main( String[] args )
    {
        try {
            for (int i = 0 ; i < 4; i++){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(new HelloCommand().execute());
                    }
                }).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果会打印:

failed
hello
hello
hello

可以看到第四个任务先打印,说明在前三个执行时,第四个被直接判定为fail,第一个打印出来。原因就是线程池只配置了三个线程,所以第四个任务没有被执行,直接fail。

当然线程池的maxQueueSize参数默认是-1,表示线程池的等待队列为0,只要核心线程池没有空闲,就fail。

4.熔断器打开。

那么就得知道什么时候熔断器会打开。

如果在10s有多于circuitBreakerSleepWindowInMilliseconds个请求到达,而且有多于circuitBreakerErrorThresholdPercentage百分比的请求失败,则会导致熔断器打开,后续的circuitBreakerSleepWindowInMilliseconds时间段内的请求会直接fail。

public class HelloCommand extends HystrixCommand<String> {
    protected HelloCommand() {
        super(
                Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("example"))
                        .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(500)
                                .withCircuitBreakerRequestVolumeThreshold(3)
                                .withCircuitBreakerErrorThresholdPercentage(75))
                        .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(100))
        );
    }

    @Override
    protected String run() throws Exception {
        Thread.sleep(1000);
        return "hello";
    }

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

main:

public class App 
{
    public static void main( String[] args )
    {
        try {
            for (int i = 0 ; i < 4; i++){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(new HelloCommand().execute());
                    }
                }).start();
                Thread.sleep(1000);
            }
            for (int i = 0 ; i < 4; i++){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(new HelloCommand().execute());
                    }
                }).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果:

failed
failed
failed
failed
failed
failed
failed
failed

总共会有8个failed打印,因为总共8个任务。

但是前四个是间隔一定时间打印一个,后面四个是同时秒打出来。

因为配置了circuitBreakerSleepWindowInMilliseconds为3。第一个for循环里的四个任务正好保证了每10秒内有大于3个任务达到,那么会触发熔断器监控逻辑,这个四个任务执行时间是1s,而超时阈值是0.5s,那么每一个任务最重都会超时。所以第四个任务fail之后,熔断器已经打开了。这四个任务会执行到run方法,所以是执行了0.5s才打印的。

第二个for循环里的任务根本不会执行,因为执行时熔断器打开了,没有sleep直到超时,而是直接秒fail,所以同时打印。

猜你喜欢

转载自blog.csdn.net/u010900754/article/details/82563466
今日推荐