序
本文主要研究一下sentinel的DegradeSlot
DegradeSlot
com/alibaba/csp/sentinel/slots/block/degrade/DegradeSlot.java
public class DegradeSlot extends AbstractLinkedProcessorSlot {
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, Object... args)
throws Throwable {
DegradeRuleManager.checkDegrade(resourceWrapper, context, node, count);
fireEntry(context, resourceWrapper, node, count, args);
}
@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
fireExit(context, resourceWrapper, count, args);
}
}
- 调用DegradeRuleManager.checkDegrade进行降级规则检测
DegradeRuleManager
com/alibaba/csp/sentinel/slots/block/degrade/DegradeRuleManager.java
public class DegradeRuleManager {
private static volatile Map> degradeRules
= new ConcurrentHashMap>();
final static RulePropertyListener listener = new RulePropertyListener();
private static SentinelProperty> currentProperty
= new DynamicSentinelProperty>();
static {
currentProperty.addListener(listener);
}
/**
* Listen to the {@link SentinelProperty} for {@link DegradeRule}s. The property is the source
* of {@link DegradeRule}s. Degrade rules can also be set by {@link #loadRules(List)} directly.
*
* @param property the property to listen.
*/
public static void register2Property(SentinelProperty> property) {
synchronized (listener) {
currentProperty.removeListener(listener);
property.addListener(listener);
currentProperty = property;
}
}
public static void checkDegrade(ResourceWrapper resource, Context context, DefaultNode node, int count)
throws BlockException {
if (degradeRules == null) {
return;
}
List rules = degradeRules.get(resource.getName());
if (rules == null) {
return;
}
for (DegradeRule rule : rules) {
if (!rule.passCheck(context, node, count)) {
throw new DegradeException(rule.getLimitApp());
}
}
}
//......
}
- checkDegrade根据资源名称获取对应的降级规则,然后挨个遍历检查
DegradeRule
com/alibaba/csp/sentinel/slots/block/degrade/DegradeRule.java
/**
*
* Degrade is used when the resources are in an unstable state, these resources
* will be degraded within the next defined time window. There are two ways to
* measure whether a resource is stable or not:
*
*
* -
* Average response time ({@code DEGRADE_GRADE_RT}): When
* the average RT exceeds the threshold ('count' in 'DegradeRule', in milliseconds), the
* resource enters a quasi-degraded state. If the RT of next coming 5
* requests still exceed this threshold, this resource will be downgraded, which
* means that in the next time window (defined in 'timeWindow', in seconds) all the
* access to this resource will be blocked.
*
* -
* Exception ratio: When the ratio of exception count per second and the
* success qps exceeds the threshold, access to the resource will be blocked in
* the coming window.
*
*
*
* @author jialiang.linjl
*/
public class DegradeRule extends AbstractRule {
private static final int RT_MAX_EXCEED_N = 5;
private static ScheduledExecutorService pool = Executors.newScheduledThreadPool(
Runtime.getRuntime().availableProcessors(), new NamedThreadFactory("sentinel-degrade-reset-task", true));
/**
* RT threshold or exception ratio threshold count.
*/
private double count;
/**
* Degrade recover timeout (in seconds) when degradation occurs.
*/
private int timeWindow;
/**
* Degrade strategy (0: average RT, 1: exception ratio).
*/
private int grade = RuleConstant.DEGRADE_GRADE_RT;
private volatile boolean cut = false;
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
private AtomicLong passCount = new AtomicLong(0);
private final Object lock = new Object();
//......
@Override
public boolean passCheck(Context context, DefaultNode node, int acquireCount, Object... args) {
if (cut) {
return false;
}
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;
}
// Sentinel will degrade the service only if count exceeds.
if (passCount.incrementAndGet() < RT_MAX_EXCEED_N) {
return true;
}
} else {
double exception = clusterNode.exceptionQps();
double success = clusterNode.successQps();
long total = clusterNode.totalQps();
// if total qps less than RT_MAX_EXCEED_N, pass.
if (total < RT_MAX_EXCEED_N) {
return true;
}
if (success == 0) {
return exception < RT_MAX_EXCEED_N;
}
if (exception / (success + exception) < count) {
return true;
}
}
synchronized (lock) {
if (!cut) {
// Automatically degrade.
cut = 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.getPassCount().set(0);
rule.setCut(false);
}
}
}
- 这个passCheck根据平均响应时间以及异常个数等进行降级判断
- 触发降级时标志cut为true,然后启动一个ResetTask,在指定时间窗口之后重置cut为false并清空passCount计数
小结
sentinel的DegradeSlot主要依据平均响应时间以及异常次数来判断,进入降级模式时启动定时任务在指定时间窗口重置相关计数,恢复到正常模式。
doc
- DegradeSlot