Hystrix CircuitBreakerSleepWindowInMilliseconds 无法按预期工作
Hystrix CircuitBreakerSleepWindowInMilliseconds doesn't work as expected
我正在测试 Hystrix CircuitBreaker 实施。这是命令 class 的样子:
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();
}
}
在测试中我执行后续步骤:
@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 毫秒(长时间)。在我的测试用例中,我希望 CommandOne.runCount = 10。
但实际上我收到了 150 到 200 次调用 MyExternalService.callMethod() (CommandOne.runCount = (150-200)。为什么会这样?我做错了什么?
根据 Hystrix docs 运行状况快照将每 500 毫秒拍摄一次(默认情况下)。这意味着 hystrix 在前 500 毫秒内发生的一切都不会影响断路器状态。在您的示例中,您获得了 runCount
的随机值,因为每次您的机器每 500 毫秒执行一次请求的随机值,并且仅在该时间间隔电路状态更新和关闭之后。
请看一个稍微简化的例子:
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);
}
在这个例子中我添加了:
withMetricsHealthSnapshotIntervalInMilliseconds(50)
允许 hystrix 每 50 毫秒拍摄一次快照。
Thread.sleep(100);
让请求慢一点,没有它它们会比 50 毫秒快,我们将面临最初的问题。
尽管进行了所有这些修改,我还是看到了一些随机故障。在此之后我得出结论,像这样测试 hystrix 不是一个好主意。我们可以使用:
代替它
1) Fallback/Success flow behavior by manually setting open/close circuit state.
2)
我正在测试 Hystrix CircuitBreaker 实施。这是命令 class 的样子:
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();
}
}
在测试中我执行后续步骤:
@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 毫秒(长时间)。在我的测试用例中,我希望 CommandOne.runCount = 10。 但实际上我收到了 150 到 200 次调用 MyExternalService.callMethod() (CommandOne.runCount = (150-200)。为什么会这样?我做错了什么?
根据 Hystrix docs 运行状况快照将每 500 毫秒拍摄一次(默认情况下)。这意味着 hystrix 在前 500 毫秒内发生的一切都不会影响断路器状态。在您的示例中,您获得了 runCount
的随机值,因为每次您的机器每 500 毫秒执行一次请求的随机值,并且仅在该时间间隔电路状态更新和关闭之后。
请看一个稍微简化的例子:
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);
}
在这个例子中我添加了:
withMetricsHealthSnapshotIntervalInMilliseconds(50)
允许 hystrix 每 50 毫秒拍摄一次快照。Thread.sleep(100);
让请求慢一点,没有它它们会比 50 毫秒快,我们将面临最初的问题。
尽管进行了所有这些修改,我还是看到了一些随机故障。在此之后我得出结论,像这样测试 hystrix 不是一个好主意。我们可以使用:
代替它1) Fallback/Success flow behavior by manually setting open/close circuit state.
2)