Hystrix CircuitBreakerSleepWindowInMilliseconds无法正常工作 [英] Hystrix CircuitBreakerSleepWindowInMilliseconds doesn't work as expected

查看:342
本文介绍了Hystrix CircuitBreakerSleepWindowInMilliseconds无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在测试Hystrix CircuitBreaker实施.这是命令类的样子:

I am testing Hystrix CircuitBreaker implementation. This is how command class looks like:

public class CommandOne extends HystrixCommand<String>
{
    private MyExternalService service;    
    public static int runCount = 0;

    public CommandGetPunterUnpayoutExternalBets(MyExternalServoce service)
    {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("AAA"))
                .andThreadPoolPropertiesDefaults(
                        HystrixThreadPoolProperties.Setter().
                         .withMetricsRollingStatisticalWindowInMilliseconds(10000))
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withCircuitBreakerEnabled(true)
                        .withCircuitBreakerErrorThresholdPercentage(20)
                        .withCircuitBreakerRequestVolumeThreshold(10)
                        .withExecutionTimeoutInMilliseconds(30)
                        .withCircuitBreakerSleepWindowInMilliseconds(100000)));

        this.service = service;
    }


    @Override
    protected String run()
    {
        run++;
        return service.callMethod();
    }


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

命令的调用方式如下:

public class AnotherClass
{
    private MyExternalServoce service; 

    public String callCmd()
    {
        CommandOne command = new CommandOne(service);
        return command.execute();
    }
}

在测试中,我执行下一步:

In test I perform next steps:

@Test
    public void test()
{
    AnotherClass anotherClass = new AnotherClass();

    // stubbing exception on my service
    when(service.callMethod()).thenThrow(new RuntimeException());
    for (int i = 0; i < 1000; i++)
        {
             anotherClass.callCmd();
        }
    System.out.println("Run method was called times = " + CommandOne.runCount);
}

我期望使用给定的命令配置:MyExternalService.callMethod()应​​该被调用10次(RequestVolumeThreshold),此后不应被调用100000 ms(长时间).在我的测试用例中,我希望CommandOne.runCount = 10.但是实际上,我收到了150到200个MyExternalService.callMethod()(CommandOne.runCount =(150-200).为什么会发生呢?我做错了什么?

What I expect with the configuration of command given: MyExternalService.callMethod() should be called 10 times (RequestVolumeThreshold) and after that not being called 100000 ms (long time). In my test case I expect that CommandOne.runCount = 10. But in reality I am getting from 150 to 200 calls of MyExternalService.callMethod() (CommandOne.runCount = (150-200). Why does it happening? What I did wrong?

推荐答案

根据Hystrix docs 健康状况快照每500毫秒拍摄一次(默认情况下).这意味着在最初的500ms内,hystrix发生的一切都不会影响断路器的状态.在您的示例中,您获得了 runCount 的随机值,因为每次您的计算机每500毫秒执行一次随机请求值时,并且仅在该时间间隔之后,电路状态才会更新和关闭.

According to Hystrix docs health snapshot will be taken once per 500ms ( by default ). Which means that everything what happens with hystrix during first 500ms will not affect circuit breaker status. In your example you got random value of runCount because each time your machine executed random value of requests per 500 ms, and only after that time interval circuit state was updated and closed.

请看一个简化的示例:

 public class CommandOne extends HystrixCommand<String> {

    private String content;
    public static int runCount = 0;


    public CommandOne(String s) {
        super(Setter.withGroupKey
                (HystrixCommandGroupKey.Factory.asKey("SnapshotIntervalTest"))
                .andCommandPropertiesDefaults(
                        HystrixCommandProperties.Setter()
                                .withCircuitBreakerSleepWindowInMilliseconds(500000)
                                .withCircuitBreakerRequestVolumeThreshold(9)
                                .withMetricsHealthSnapshotIntervalInMilliseconds(50)
                                .withMetricsRollingStatisticalWindowInMilliseconds(100000)
                )
        );
        this.content = s;
    }

    @Override
    public String run() throws Exception {
        Thread.sleep(100);
        runCount++;
        if ("".equals(content)) {
            throw new Exception();
        }
        return content;
    }

    @Override
    protected String getFallback() {
        return "FAILURE-" + content;
    }

}

    @Test
    void test() {

        for (int i = 0; i < 100; i++) {
            CommandOne commandOne = new CommandOne();
            commandOne.execute();
        }
        Assertions.assertEquals(10, CommandOne.runCount);
    }

在此示例中,我添加了:

In this example I've added:

  • withMetricsHealthSnapshotIntervalInMilliseconds(50),允许hystrix每50毫秒拍摄一次快照.
  • Thread.sleep(100); 使请求变慢一些,没有它,它们将比50 ms快,我们将面临最初的问题.
  • withMetricsHealthSnapshotIntervalInMilliseconds(50) to allow hystrix to take snapshots each 50ms.
  • Thread.sleep(100); to make requests a bit slower, without it they will be faster then 50 ms and we will face initial issue.

尽管进行了所有这些修改,但我还是看到了一些随机故障.在此之后,我得出结论,像这样测试hystrix不是一个好主意.代替它,我们可以使用:

Despite of all these modifications I've seen some random failures. After this I came to conclusion that testing hystrix like this is not a good idea. Instead of it we could use:

1) Fallback/成功通过手动设置开/关电路状态来实现流动行为.

2)配置测试

这篇关于Hystrix CircuitBreakerSleepWindowInMilliseconds无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆