0. 前言
- SpringBoot版本:2.1.9.RELEASE
- SpringCloud版本:Greenwich.SR4
1. HystrixCircuitBreaker
public interface HystrixCircuitBreaker {
// 是否允许请求
public boolean allowRequest();
// 断路器是否开启
public boolean isOpen();
// 关闭断路器
void markSuccess();
}
2. HystrixCircuitBreakerImpl
static class HystrixCircuitBreakerImpl implements HystrixCircuitBreaker {
// 熔断配置信息
private final HystrixCommandProperties properties;
// 熔断指标信息
private final HystrixCommandMetrics metrics;
// 断路器是否开启
private AtomicBoolean circuitOpen = new AtomicBoolean(false);
// 记录断路器开启或最近测试请求时间
private AtomicLong circuitOpenedOrLastTestedTime = new AtomicLong();
protected HystrixCircuitBreakerImpl(HystrixCommandKey key, HystrixCommandGroupKey commandGroup, HystrixCommandProperties properties, HystrixCommandMetrics metrics) {
this.properties = properties;
this.metrics = metrics;
}
public void markSuccess() {
if (circuitOpen.get()) {
// 如果断路器开启,则关闭
if (circuitOpen.compareAndSet(true, false)) {
// 重置熔断指标信息
metrics.resetStream();
}
}
}
@Override
public boolean allowRequest() {
if (properties.circuitBreakerForceOpen().get()) {
// 如果配置了断路器强制开启,返回 false 不允许发起请求
return false;
}
if (properties.circuitBreakerForceClosed().get()) {
// 如果配置了断路器强制关闭,返回 true 允许发起请求
// 但是还是要调用 isOpen() 方法处理断路器相关信息
isOpen();
return true;
}
// 两个条件满足其一则允许请求:
// 1. 断路器认为是关闭的
// 2. 允许尝试一次请求
return !isOpen() || allowSingleTest();
}
public boolean allowSingleTest() {
long timeCircuitOpenedOrWasLastTested = circuitOpenedOrLastTestedTime.get();
if (circuitOpen.get() && System.currentTimeMillis() > timeCircuitOpenedOrWasLastTested + properties.circuitBreakerSleepWindowInMilliseconds().get()) {
if (circuitOpenedOrLastTestedTime.compareAndSet(timeCircuitOpenedOrWasLastTested, System.currentTimeMillis())) {
// 断路器开启后,每隔一定时间(默认5s)允许尝试一次请求
return true;
}
}
return false;
}
@Override
public boolean isOpen() {
if (circuitOpen.get()) {
// 断路器开启,返回 true
return true;
}
// 获取健康指标信息
HealthCounts health = metrics.getHealthCounts();
if (health.getTotalRequests() < properties.circuitBreakerRequestVolumeThreshold().get()) {
// 如果在最近10s(默认)请求总数小于20次(默认)
// 则认为断路器是关闭的
return false;
}
if (health.getErrorPercentage() < properties.circuitBreakerErrorThresholdPercentage().get()) {
// 如果在最近10s(默认)请求失败率小于50%(默认)
// 则认为断路器是关闭的
return false;
} else {
// 记录断路器状态为开启
if (circuitOpen.compareAndSet(false, true)) {
circuitOpenedOrLastTestedTime.set(System.currentTimeMillis());
return true;
} else {
return true;
}
}
}
}
3. 总结
-
断路规则:
-
断路器开启后,单位时间内允许尝试一次请求:
学习参考:掘金小册《SpringCloudNetflix 源码解读与原理分析》