sentinel 熔断降级
官网:https://sentinelguard.io/zh-cn/docs/circuit-breaking.html
熔断降级
熔断降级:服务由于响应慢、异常等原因触发熔断策略后,快速失败,避免线程堆积造成服务雪崩(熔断降级通常在调用端配置)
熔断策略
# 慢调用比例:SLOW_REQUEST_RATIO,以慢调用比例作为阈值
慢调用:如果一个请求的响应时间需要大于设置的慢调用响应时间(RT),该请求统计为慢调用;
熔断触发:单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,
并且慢调用的比例大于阈值,在熔断时长内自动触发熔断(调用方法时,抛出DegradeException)
熔断恢复:在熔断时长后,熔断器进入探测恢复状态(half-open状态),
如果接下来的请求响应时间 < 设置的慢调用响应时间,则结束熔断
如果接下来的请求响应时间 > 设置的慢调用响应时间,则继续在熔断时长内保持熔断
# 异常比例 :ERROR_RATIO,以请求异常比例作为阀值,阈值范围是[0.0, 1.0]
异常请求:请求调用抛出异常,则该请求统计为异常请求
熔断触发:单位统计时长(statIntervalMs)内请求数目 > 设置的最小请求数目,
并且异常的比例 > 阈值,在熔断时长内自动被熔断
熔断恢复:在熔断时长后,熔断器进入探测恢复状态(HALF-OPEN 状态),
如果接下来的一个请求执行成功,则结束熔断;
如果请求执行失败,则继续在熔断时长内保持熔断
# 异常数:ERROR_COUNT,以异常请求数作为阀值
异常请求:请求调用抛出异常,则该请求统计为异常请求
熔断触发:单位统计时长(statIntervalMs)内请求数目 > 设置的最小请求数目,
并且异常请求 > 设置的异常请求数阀值,在熔断时长内自动被熔断
熔断恢复:在熔断时长后,熔断器进入探测恢复状态(HALF-OPEN 状态),
如果接下来的一个请求执行成功,则结束熔断;
如果请求执行失败,则继续在熔断时长内保持熔断
DegradeRule:熔断降级规则
public class DegradeRule extends AbstractRule {
private int grade = 0; //熔断策略,支持慢调用比例(默认)、异常比例、异常数策略
private double count; //限流阀值
private int timeWindow; //熔断时间窗口,单位为秒
private int minRequestAmount = 5; //最小请求数
private double slowRatioThreshold = 1.0D; //慢调用比例阈值
private int statIntervalMs = 1000; //统计时间窗口,默认1s
public DegradeRule() {
}
AbstractRule
public abstract class AbstractRule implements Rule {
private String resource; //限流资源
private String limitApp; //调用来源、default、other
public AbstractRule() {
}
实现原理
DegradeSlot
@SpiOrder(-1000)
public class DegradeSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
public DegradeSlot() {
}
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args) throws Throwable {
this.performChecking(context, resourceWrapper); //检查熔断规则,如果触发熔断,直接抛出DegradeException异常
this.fireEntry(context, resourceWrapper, node, count, prioritized, args);
//追星后续限流操作
}
void performChecking(Context context, ResourceWrapper r) throws BlockException {
List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(r.getName());
//获取资源相关的断路器
if (circuitBreakers != null && !circuitBreakers.isEmpty()) {
Iterator var4 = circuitBreakers.iterator();
CircuitBreaker cb;
do {
if (!var4.hasNext()) {
return;
}
cb = (CircuitBreaker)var4.next();
} while(cb.tryPass(context)); //熔断窗口到期,检查单词请求是否可以通过
throw new DegradeException(cb.getRule().getLimitApp(), cb.getRule());
//熔断检查未通过,抛出DegradeException异常
}
}
public void exit(Context context, ResourceWrapper r, int count, Object... args) {
Entry curEntry = context.getCurEntry();
if (curEntry.getBlockError() != null) {
this.fireExit(context, r, count, args);
} else {
List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(r.getName());
if (circuitBreakers != null && !circuitBreakers.isEmpty()) {
if (curEntry.getBlockError() == null) {
Iterator var7 = circuitBreakers.iterator();
while(var7.hasNext()) {
CircuitBreaker circuitBreaker = (CircuitBreaker)var7.next();
circuitBreaker.onRequestComplete(context);
}
}
this.fireExit(context, r, count, args);
} else {
this.fireExit(context, r, count, args);
}
}
}
}
CircuitBreaker
public interface CircuitBreaker {
DegradeRule getRule();
boolean tryPass(Context var1);
CircuitBreaker.State currentState();
void onRequestComplete(Context var1);
public static enum State {
OPEN,
HALF_OPEN,
CLOSED;
private State() {
}
}
}
AbstractCircuitBreaker
public abstract class AbstractCircuitBreaker implements CircuitBreaker {
protected final DegradeRule rule;
protected final int recoveryTimeoutMs;
private final EventObserverRegistry observerRegistry;
protected final AtomicReference<State> currentState;
protected volatile long nextRetryTimestamp;
public AbstractCircuitBreaker(DegradeRule rule) {
this(rule, EventObserverRegistry.getInstance());
}
AbstractCircuitBreaker(DegradeRule rule, EventObserverRegistry observerRegistry) {
this.currentState = new AtomicReference(State.CLOSED);
AssertUtil.notNull(observerRegistry, "observerRegistry cannot be null");
if (!DegradeRuleManager.isValidRule(rule)) {
throw new IllegalArgumentException("Invalid DegradeRule: " + rule);
} else {
this.observerRegistry = observerRegistry;
this.rule = rule;
this.recoveryTimeoutMs = rule.getTimeWindow() * 1000;
}
}
public DegradeRule getRule() {
return this.rule;
}
public State currentState() {
return (State)this.currentState.get();
}
public boolean tryPass(Context context) { //熔断检查
if (this.currentState.get() == State.CLOSED) { //断路器为closed,返回true
return true;
} else if (this.currentState.get() != State.OPEN) { //断路器状态不为open,返回false
return false;
} else {
return this.retryTimeoutArrived() && this.fromOpenToHalfOpen(context);
} //判断是否是请求重试时间,如果不是,直接返回false
//如果是,断路器状态设置为HalfOpen,异步执行单次请求,
//如果单次请求不通过,断路器状态切换为open,
//如果单次请求通过,返回true,可执行后续限流操作
}
abstract void resetStat();
protected boolean retryTimeoutArrived() {
return TimeUtil.currentTimeMillis() >= this.nextRetryTimestamp;
} //判断是否为请求重试时间
protected void updateNextRetryTimestamp() {
this.nextRetryTimestamp = TimeUtil.currentTimeMillis() + (long)this.recoveryTimeoutMs;
} //下次重试时间:当前时间 + recoveryTimeoutMs(即rule.getTimeWindow() * 1000)
protected boolean fromCloseToOpen(double snapshotValue) {
State prev = State.CLOSED;
if (this.currentState.compareAndSet(prev, State.OPEN)) {
this.updateNextRetryTimestamp();
this.notifyObservers(prev, State.OPEN, snapshotValue);
return true;
} else {
return false;