共计 3727 个字符,预计需要花费 10 分钟才能阅读完成。
hystrix – Fallback 是怎么调用的提到了 allowRequest 办法,咱们看看这里是做了哪些。
public boolean allowRequest() {
// 配置了强制熔断,间接返回 false
if (properties.circuitBreakerForceOpen().get()) {
// properties have asked us to force the circuit open so we will allow NO requests
return false;
}
// 强制敞开
if (properties.circuitBreakerForceClosed().get()) {// we still want to allow isOpen() to perform it's calculations so we simulate normal behavior
isOpen();
// properties have asked us to ignore errors so we will ignore the results of isOpen and just allow all traffic through
return true;
}
return !isOpen() || allowSingleTest();
}
public boolean isOpen() {
// 获取熔断器的状态,true 就是开
if (circuitOpen.get()) {
// 如果是开的,还是返回 ture,留给半开的时候用
return true;
}
// 如果是关的,获取 HealthCounts 信息
HealthCounts health = metrics.getHealthCounts();
// 以后的申请数如果小于设置的阈值,就间接返回 false,阐明没开
// 比方咱们设置了 20,此时才 19,也是没有开的
// 这个值是样品数量的值,只有足够数量的样品,才比拟精确
if (health.getTotalRequests() < properties.circuitBreakerRequestVolumeThreshold().get()) {
// we are not past the minimum volume threshold for the statisticalWindow so we'll return false immediately and not calculate anything
return false;
}
// 谬误比例小于设定的值,比方谬误的比例超过 50%,就开启熔断
if (health.getErrorPercentage() < properties.circuitBreakerErrorThresholdPercentage().get()) {return false;} else {
// 这边设置工夫,用于半开状态
if (circuitOpen.compareAndSet(false, true)) {
// if the previousValue was false then we want to set the currentTime
circuitOpenedOrLastTestedTime.set(System.currentTimeMillis());
return true;
} else {
// How could previousValue be true? If another thread was going through this code at the same time a race-condition could have
// caused another thread to set it to true already even though we were in the process of doing the same
// In this case, we know the circuit is open, so let the other thread set the currentTime and report back that the circuit is open
return true;
}
}
}
流程图如下:
半开状态
下面还有一个办法,allowSingleTest。这个是用于解决半开的时候。
咱们下面晓得,当熔断的时候,会保留一个值,circuitOpenedOrLastTestedTime。这个值加上设置的休眠工夫和以后工夫做比拟,看看能不能允许尝试拜访一次。
public boolean allowSingleTest() {long timeCircuitOpenedOrWasLastTested = circuitOpenedOrLastTestedTime.get();
// 熔断器开的时候,并且以后工夫 > 熔断工夫 + 休眠工夫
// 也就是说休眠工夫设置为 5,那 5 秒后给他一个机会看看能不能拜访,也就是半开状态
// 而后从新设置 circuitOpenedOrLastTestedTime
if (circuitOpen.get() && System.currentTimeMillis() > timeCircuitOpenedOrWasLastTested + properties.circuitBreakerSleepWindowInMilliseconds().get()) {if (circuitOpenedOrLastTestedTime.compareAndSet(timeCircuitOpenedOrWasLastTested, System.currentTimeMillis())) {return true;}
}
return false;
}
HystrixCircuitBreaker 创立
allowRequest 是 HystrixCircuitBreaker 的办法,咱们略微回顾一下 command 的创立,AbstractCommand 中,会调用 initCircuitBreaker 办法。他会通过 HystrixCircuitBreaker 的 Factory 来创立的
private static HystrixCircuitBreaker initCircuitBreaker(boolean enabled, HystrixCircuitBreaker fromConstructor,
HystrixCommandGroupKey groupKey, HystrixCommandKey commandKey,
HystrixCommandProperties properties, HystrixCommandMetrics metrics) {if (enabled) {if (fromConstructor == null) {
// get the default implementation of HystrixCircuitBreaker
return HystrixCircuitBreaker.Factory.getInstance(commandKey, groupKey, properties, metrics);
} else {return fromConstructor;}
} else {return new NoOpCircuitBreaker();
}
}
在工厂中,他其实会通过缓存来获取的,也就是说每个 CommandKey 都有对应的 HystrixCircuitBreaker。如果缓存没有,则创立一个放入缓存。
public static HystrixCircuitBreaker getInstance(HystrixCommandKey key, HystrixCommandGroupKey group, HystrixCommandProperties properties, HystrixCommandMetrics metrics) {
// 从 circuitBreakersByCommand 缓存里取,key 是 CommandKey
HystrixCircuitBreaker previouslyCached = circuitBreakersByCommand.get(key.name());
if (previouslyCached != null) {return previouslyCached;}
// 缓存没有,创立一个放入缓存中
HystrixCircuitBreaker cbForCommand = circuitBreakersByCommand.putIfAbsent(key.name(), new HystrixCircuitBreakerImpl(key, group, properties, metrics));
if (cbForCommand == null) {
// this means the putIfAbsent step just created a new one so let's retrieve and return it
return circuitBreakersByCommand.get(key.name());
} else {
// this means a race occurred and while attempting to 'put' another one got there before
// and we instead retrieved it and will now return it
return cbForCommand;
}
}
正文完