В предыдущей статье был представлен основной принцип работы и текущий ограничивающий принцип дозорного. В этой статье будет проанализирован принцип понижения версии Fuse с точки зрения исходного кода. Операция предохранителя расположена в конце цепочки обработки слотов и обрабатывается классом с именем DegradeSlot, давайте взглянем на его исходный код.
@SpiOrder(-1000)
public class DegradeSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args)
throws Throwable {
//熔断降级判断
DegradeRuleManager.checkDegrade(resourceWrapper, context, node, count);
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
fireExit(context, resourceWrapper, count, args);
}
}
Исходный код очень прост, доверьте его обработку DegradeRuleManager и введите метод checkDegrade DegradeRuleManager.
public static void checkDegrade(ResourceWrapper resource, Context context, DefaultNode node, int count)
throws BlockException {
//获取资源熔断规则
Set<DegradeRule> rules = degradeRules.get(resource.getName());
if (rules == null) {
return;
}
//遍历每个熔断规则,校验是否满足熔断条件
for (DegradeRule rule : rules) {
//如果达到了熔断条件,就会抛出DegradeException的异常
if (!rule.passCheck(context, node, count)) {
throw new DegradeException(rule.getLimitApp(), rule);
}
}
}
Решение предохранителя заключается в том, чтобы судить и обрабатывать правила, установленные для ресурсов, один за другим. Если одно из условий не выполняется, выбрасывается исключение DegradeException. Итак, как принимается решение о предохранителе? Продолжайте углубляться в метод passCheck в классе DegradeRule.Прежде чем анализировать метод passCheck, мы представим несколько важных полей класса DegradeRule.
//慢请求或异常请求的计数
private double count;
//熔断窗口
private int timeWindow;
//熔断策略 (0: 慢调用, 1: 异常率, 2: 异常数)
private int grade = RuleConstant.DEGRADE_GRADE_RT;
/**
* 针对慢调用,如果慢调用数小于其值(默认为5),是不会触发熔断的
*
* @since 1.7.0
*/
private int rtSlowRequestAmount = RuleConstant.DEGRADE_DEFAULT_SLOW_REQUEST_AMOUNT;
/**
* 针对异常率,如果异常数小于其值(默认为5),是不会触发熔断的
*
* @since 1.7.0
*/
private int minRequestAmount = RuleConstant.DEGRADE_DEFAULT_MIN_REQUEST_AMOUNT;
Принцип реализации слияния заключается в том, чтобы просто оценить, превышает ли соответствующая статистика подсчета пороговое значение в соответствии с конкретной стратегией слияния, установленной в течение заданного времени окна, и если оно превышает, механизм слияния будет запущен. Погрузитесь в исходный код passCheck
//慢调用计数
private AtomicLong passCount = new AtomicLong(0);
//熔断降级标记位,如果为true,则表示触发了熔断
private final AtomicBoolean cut = new AtomicBoolean(false);
public boolean passCheck(Context context, DefaultNode node, int acquireCount, Object... args) {
//如果标记位为真,表示已触发熔断
if (cut.get()) {
return false;
}
//获取资源计数统计node
ClusterNode clusterNode = ClusterBuilderSlot.getClusterNode(this.getResource());
if (clusterNode == null) {
return true;
}
//如果熔断降级策略为慢调用
if (grade == RuleConstant.DEGRADE_GRADE_RT) {
//获取慢调用平均响应时间
double rt = clusterNode.avgRt();
//如果调用平均响应时间小于设定的门限值,则重置慢调用计数统计
if (rt < this.count) {
passCount.set(0);
return true;
}
//如果慢调用数小于默认的最小门限数(5),则不进行熔断降级
if (passCount.incrementAndGet() < rtSlowRequestAmount) {
return true;
}
//如果熔断降级策略是异常率
} else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) {
//每秒的异常数
double exception = clusterNode.exceptionQps();
//每秒成功调用数
double success = clusterNode.successQps();
//每秒总调用数
double total = clusterNode.totalQps();
//如果总调用数小于默认的门限值(5),则不会触发熔断降级
if (total < minRequestAmount) {
return true;
}
//此句需要好好理解下,它表达的意思是:在异常数小于最小门限的条件是不进行熔断降级的,但前提是所用调用都不能全是异常调用
double realSuccess = success - exception;
if (realSuccess <= 0 && exception < minRequestAmount) {
return true;
}
//异常率小于设置的门限,则不熔断降级
if (exception / success < count) {
return true;
}
//如果熔断降级策略是异常数
} else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) {
//注意,这个异常数是每分钟统计的
double exception = clusterNode.totalException();
//小于设置的门限值,则不熔断
if (exception < count) {
return true;
}
}
//如果走到了这里,则表示将要触发熔断降级了
//重置慢调用统计时间窗口,此处用了CAS的方法来设置标志位,防止并发。时间窗口的重置是依赖于定时任务来完成的,当timeWindow时间后,会重置熔断标志位和计数统计
if (cut.compareAndSet(false, true)) {
ResetTask resetTask = new ResetTask(this);
pool.schedule(resetTask, timeWindow, TimeUnit.SECONDS);
}
return false;
}
//重置时间窗口
private static final class ResetTask implements Runnable {
private DegradeRule rule;
ResetTask(DegradeRule rule) {
this.rule = rule;
}
@Override
public void run() {
//重置慢调用计数
rule.passCount.set(0);
//熔断标志位
rule.cut.set(false);
}
}
Приведенный выше код описывает основной процесс слияния и понижения версии.Для приведенного выше кода следует отметить, что:
- Медленные вызовы осуществляются черезвременное окноЧтобы подсчитать количество медленных вызовов для достижения
- Исключительная норма дляв секундуСоотношение количества исключений и количества успехов для определения выполнения условий срабатывания
- Количество исключений длякаждую минутуКоличество аномальной статистики для достижения
При срабатывании автоматического выключателя бит флага будет установлен в значение true и будет длиться в течение длительного времени Window, которое задается разработчиком при настройке правила понижения уровня автоматического выключателя. Выше приведен процесс реализации полного понижения версии предохранителя.С точки зрения кода, окно предохранителя обновляется с помощью временной задачи, и дизайн является относительно новым.