在使用Hystrix实现熔断的过程中遇到了两个问题
1、在修改了熔断配置之后不生效的问题
2、熔断后不恢复的问题
对于第一个问题,查看hystrix源码可以看到,如果有缓存配置是优先使用的缓存的,因此如果配置更新,必须要更新缓存,不能使用Hystrix.reset()方法来更新缓存,这个方法清理全局缓存,会影响其他commandkey的熔断状态。
public static HystrixCircuitBreaker getInstance(HystrixCommandKey key, HystrixCommandGroupKey group, HystrixCommandProperties properties, HystrixCommandMetrics metrics) {
// this should find it for all but the first time
HystrixCircuitBreaker previouslyCached = circuitBreakersByCommand.get(key.name());
if (previouslyCached != null) {
return previouslyCached;
}
官方提供的方法是通过archaius动态更新:https://github.com/Netflix/Hystrix/wiki/Configuration
Hystrix uses Archaius for the default implementation of properties for configuration.
实现接口com.netflix.config.PolledConfigurationSource,将对应的commandkey通过形如下面的key来放入poll方法响应的map中,hystrix会根据这个key自动更新缓存
hystrix.command.HystrixCommandKey.execution.isolation.thread.timeoutInMilliseconds
第二个问题经过debughystrix源码发现是由于,使用了响应式的调用,hystrix使用的是V1版本的rxjava,而项目使用的是V3版本的rxjava,在V3转V1后响应给hystrixcircuitbreaker时,hystrix没有收到oncomplete事件,导致没有在断路器半开状态时调用成功关闭断路器。
在com.netflix.hystrix.AbstractCommand类中实现了断路器的控制逻辑:
可以看到在onCompleted的观察者逻辑中会将断路器markSuccess
private Observable<R> executeCommandAndObserve(final AbstractCommand<R> _cmd) {
final HystrixRequestContext currentRequestContext = HystrixRequestContext.getContextForCurrentThread();
final Action1<R> markEmits = new Action1<R>() {
@Override
public void call(R r) {
if (shouldOutputOnNextEvents()) {
executionResult = executionResult.addEvent(HystrixEventType.EMIT);
eventNotifier.markEvent(HystrixEventType.EMIT, commandKey);
}
if (commandIsScalar()) {
long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
eventNotifier.markCommandExecution(getCommandKey(), properties.executionIsolationStrategy().get(), (int) latency, executionResult.getOrderedList());
eventNotifier.markEvent(HystrixEventType.SUCCESS, commandKey);
executionResult = executionResult.addEvent((int) latency, HystrixEventType.SUCCESS);
circuitBreaker.markSuccess();
}
}
};
final Action0 markOnCompleted = new Action0() {
@Override
public void call() {
if (!commandIsScalar()) {
long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
eventNotifier.markCommandExecution(getCommandKey(), properties.executionIsolationStrategy().get(), (int) latency, executionResult.getOrderedList());
eventNotifier.markEvent(HystrixEventType.SUCCESS, commandKey);
executionResult = executionResult.addEvent((int) latency, HystrixEventType.SUCCESS);
circuitBreaker.markSuccess();
}
}
};
目前想到的解决办法是一种是在接收调用服务响应时blockingfirst(),但是这样会导致异步调用变成同步,还有一种是在调用服务的Observable的onnext方法中添加onCompleted事件,来通知hystrix调用服务接收到了complete事件,但是这样就只能接收到单个onNext事件,两种都有缺点,还有想到更好的解决办法。