在以前的文章中,分析了Sentinel如何统计数据指标的。本篇文章主要是分析调用链路上的一些功能插槽的功能和实现,包括系统自适应、黑白名单控制、流量控制、熔断降级四个功能。node
在分析各类功能插槽以前,先看一下Sentinel对规则的定义。git
Sentinel使用Rule表示规则,Rule是一个接口,Rule只有一个方法,passCheck(),表示规则是否经过。github
AbstractRule实现了Rule,是一个抽象类,里面定义了这个规则属于的资源,限制的app。全部具体的规则都是继承该规则。api
当定义了具体的规则以后,须要加载规则到系统中,这个加载过程是由规则管理器负责的,好比定义了系统自适应规则SystemRule,会由对应的规则管理器SystemRuleManager加载该规则。 下面就以SystemRuleManager为例,分析规则的加载。缓存
每个规则管理器中都会有一个继承了SimplePropertyListener规则改变处理器做为变量,当规则改变以后,作相关的更新处理工做。每一个规则管理器中会定义一个内部类做为该变量的具体实现,好比SystemRuleManager:bash
//建立一个文件处理器
private final static SystemPropertyListener listener = new SystemPropertyListener();
//定义一个处理该规则的处理器类
static class SystemPropertyListener extends SimplePropertyListener<List<SystemRule>>{
。。。
}
复制代码
能够看到,SystemRuleManager建立了一个SystemPropertyListener做为文件改变的处理器,SystemPropertyListener是其内部的一个内部类。并发
规则管理器中还会定义一个SentinelProperty,SentinelProperty表明Sentinel中的配置信息,在这个地方就是表明配置的规则。而后会将定义的规则处理器添加给规则,当规则变动的时候,使用对应的规则处理器进行处理。app
private static SentinelProperty<List<SystemRule>> currentProperty = new DynamicSentinelProperty<List<SystemRule>>();
currentProperty.addListener(listener);
复制代码
以SystemRule更新为例,当定义了规则以后,调用SystemRuleManager的loadRules()会进行规则的更新。ide
public static void loadRules(List<SystemRule> rules) {
currentProperty.updateValue(rules);
}
复制代码
调用loadRules()的时候实际上是调用DynamicSentinelProperty的updateValues()方法:ui
public boolean updateValue(T newValue) {
if (isEqual(value, newValue)) {
return false;
}
RecordLog.info("[DynamicSentinelProperty] Config will be updated to: " + newValue);
value = newValue;
for (PropertyListener<T> listener : listeners) {
listener.configUpdate(newValue);
}
return true;
}
复制代码
能够看到,DynamicSentinelProperty的updateValues()的方法中实际上是调用规则改变处理器的configUpdate()方法,因此具体是如何更新的是每一个规则管理器里面定义的内部类SimplePropertyListener。
以上就是规则的加载过程,各类规则的加载大体流程是同样的,只是具体的加载逻辑都是由本身的规则管理器中定义的SimplePropertyListener来负责更新。
系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽量跑在最大吞吐量的同时保证系统总体的稳定性。
系统保护规则是应用总体维度的,而不是资源维度的,而且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),好比 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
系统规则支持如下的模式:
Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 做为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值通常是 CPU cores * 2.5。
CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
平均 RT:当单台机器上全部入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。 并发线程数:当单台机器上全部入口流量的并发线程数达到阈值即触发系统保护。
入口 QPS:当单台机器上全部入口流量的 QPS 达到阈值即触发系统保护。
以上文字摘抄至sentinel官方文档。
SystemRule表明系统自适应保护的规则定义,定义了load、cpu、qps、rt、thread维度的参数。
public class SystemRule extends AbstractRule {
/**
* negative value means no threshold checking.
*/
private double highestSystemLoad = -1;
/**
* cpu usage, between [0, 1]
*/
private double highestCpuUsage = -1;
private double qps = -1;
private long avgRt = -1;
private long maxThread = -1;
}
复制代码
SystemRuleManager是实现系统自适应保护的核心类,负责管理系统自适应规则,包括加载更新规则,检查当前入口调用是否知足规则。
public class SystemRuleManager {
private static volatile double highestSystemLoad = Double.MAX_VALUE;
private static volatile double highestCpuUsage = Double.MAX_VALUE;
private static volatile double qps = Double.MAX_VALUE;
private static volatile long maxRt = Long.MAX_VALUE;
private static volatile long maxThread = Long.MAX_VALUE;
private static volatile boolean highestSystemLoadIsSet = false;
private static volatile boolean highestCpuUsageIsSet = false;
private static volatile boolean qpsIsSet = false;
private static volatile boolean maxRtIsSet = false;
private static volatile boolean maxThreadIsSet = false;
/**
* 是否存在指定的系统规则,便是否调用SystemRuleManager.loadRules()加载规则
*/
private static AtomicBoolean checkSystemStatus = new AtomicBoolean(false);
/**
* 一个获取系统当前的load和cpu使用的任务
*/
private static SystemStatusListener statusListener = null;
/**
* 系统规则改变后的处理器,主要将规则设置为指定的规则
*/
private final static SystemPropertyListener listener = new SystemPropertyListener();
/**
* 系统规则改变后的处理器,主要将规则设置为指定的规则
*/
private static SentinelProperty<List<SystemRule>> currentProperty = new DynamicSentinelProperty<List<SystemRule>>();
/**
*
*/
private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1,
new NamedThreadFactory("sentinel-system-status-record-task", true));
static {
checkSystemStatus.set(false);
statusListener = new SystemStatusListener();
//定时任务5秒后开始,每秒执行一次
scheduler.scheduleAtFixedRate(statusListener, 5, 1, TimeUnit.SECONDS);
currentProperty.addListener(listener);
}
...
}
复制代码
上面的参数主要含义为:
再看静态代码块,主要是初始化scheduler,设置运行的任务和频率,而且将系统规则处理器添加给currentProperty。
SystemRuleManager中会负责规则的加载,这个部分在第二小节中已经讲过。
SystemRuleManager中还有一个最重要的方法,checkSystem(),负责校验进入的请求是否知足系统自适应设置的规则。
public static void checkSystem(ResourceWrapper resourceWrapper) throws BlockException {
// Ensure the checking switch is on.
//若是没有加入系统规则,则不须要检查
if (!checkSystemStatus.get()) {
return;
}
// for inbound traffic only
//若是不是系统入口的资源,不检查
if (resourceWrapper.getType() != EntryType.IN) {
return;
}
//根据全局的ClusterNode获取数据指标,ClusterNode是一个类变量,全局惟一,类加载后生成。
// 每次经过check后再StatisticSlot中累加统计
// total qps
double currentQps = Constants.ENTRY_NODE == null ? 0.0 : Constants.ENTRY_NODE.successQps();
if (currentQps > qps) {
throw new SystemBlockException(resourceWrapper.getName(), "qps");
}
// total thread
int currentThread = Constants.ENTRY_NODE == null ? 0 : Constants.ENTRY_NODE.curThreadNum();
if (currentThread > maxThread) {
throw new SystemBlockException(resourceWrapper.getName(), "thread");
}
double rt = Constants.ENTRY_NODE == null ? 0 : Constants.ENTRY_NODE.avgRt();
if (rt > maxRt) {
throw new SystemBlockException(resourceWrapper.getName(), "rt");
}
// load. BBR algorithm.
//若是当前机器的load大于设置的值
if (highestSystemLoadIsSet && getCurrentSystemAvgLoad() > highestSystemLoad) {
if (!checkBbr(currentThread)) {
throw new SystemBlockException(resourceWrapper.getName(), "load");
}
}
// cpu usage
if (highestCpuUsageIsSet && getCurrentCpuUsage() > highestCpuUsage) {
if (!checkBbr(currentThread)) {
throw new SystemBlockException(resourceWrapper.getName(), "cpu");
}
}
}
复制代码
checkSystem()中具体的逻辑如上,具体实现原理能够参考官方文档。
SystemSlot是负责系统自适应保护的功能插槽,每个内部entry进入的时候都会进行系统自适应保护校验。SystemSlot很简单,主要是在entry()方法中调用 SystemRuleManager.checkSystem()方法进行系统自适应保护的检查,具体逻辑仍是在SystemRuleManager中。
黑白名单根据资源的请求来源(origin)限制资源是否经过,若配置白名单则只有请求来源位于白名单内时才可经过;若配置黑名单则请求来源位于黑名单时不经过,其他的请求经过。
AuthorityRule表明对黑白名单设置的规则,其中主要包括个属性设置,一个是限制的来源名称,多个来源使用逗号分隔。还须要设置限制的时白名单仍是黑名单。
private String limitApp;
private int strategy = RuleConstant.AUTHORITY_WHITE;
复制代码
AuthorityRuleManager和上一节的SystemRuleManager相似,是负责管理黑白名单的加载的。先看一下其中的属性定义:
public final class AuthorityRuleManager {
/**
* 保存权限配置,以resource为key,因此同一个resource只能有一个最新的权限规则
*/
private static Map<String, Set<AuthorityRule>> authorityRules = new ConcurrentHashMap<>();
/**
* 规则改变处理器
*/
private static final RulePropertyListener LISTENER = new RulePropertyListener();
/**
* 当前规则
*/
private static SentinelProperty<List<AuthorityRule>> currentProperty = new DynamicSentinelProperty<>();
static {
currentProperty.addListener(LISTENER);
}
}
复制代码
和SystemRuleManager相似,AuthorityRuleManager也有一个规则改变的处理器RulePropertyListener,这个RulePropertyListener是AuthorityRuleManager的一个内部类,而后也有一个表示当前配置的配置类currentProperty,当须要加载更新规则的时候,逻辑和SystemRuleManager相似,因此再也不描述。
AuthoritySlot是负责处理黑白名单的功能插槽,当entry进入的时候,调用checkBlackWhiteAuthority()进行校验。
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args)
throws Throwable {
checkBlackWhiteAuthority(resourceWrapper, context);
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
/**
* 检查黑白名单
* @param resource
* @param context
* @throws AuthorityException
*/
void checkBlackWhiteAuthority(ResourceWrapper resource, Context context) throws AuthorityException {
//获取全部的规则
Map<String, Set<AuthorityRule>> authorityRules = AuthorityRuleManager.getAuthorityRules();
if (authorityRules == null) {
return;
}
//获取指定resource的规则
Set<AuthorityRule> rules = authorityRules.get(resource.getName());
if (rules == null) {
return;
}
for (AuthorityRule rule : rules) {
if (!AuthorityRuleChecker.passCheck(rule, context)) {
throw new AuthorityException(context.getOrigin(), rule);
}
}
}
复制代码
能够看到,这个地方主要是获取全部的黑白名单规则,而后遍历调用AuthorityRuleChecker.passCheck()进行校验,校验的具体逻辑很简单,就不在此描述了。
流量控制原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
FlowRule表明流量控制规则,定义了流量控制的各类参数。
public class FlowRule extends AbstractRule {
/**
* The threshold type of flow control (0: thread count, 1: QPS).
*/
private int grade = RuleConstant.FLOW_GRADE_QPS;
/**
* Flow control threshold count.
*/
private double count;
/**
* Flow control strategy based on invocation chain.
*
* {@link RuleConstant#STRATEGY_DIRECT} for direct flow control (by origin);
* {@link RuleConstant#STRATEGY_RELATE} for relevant flow control (with relevant resource);
* {@link RuleConstant#STRATEGY_CHAIN} for chain flow control (by entrance resource).
*/
private int strategy = RuleConstant.STRATEGY_DIRECT;
/**
* Reference resource in flow control with relevant resource or context.
*/
private String refResource;
/**
* Rate limiter control behavior.
* 0. default(reject directly), 1. warm up, 2. rate limiter, 3. warm up + rate limiter
*/
private int controlBehavior = RuleConstant.CONTROL_BEHAVIOR_DEFAULT;
private int warmUpPeriodSec = 10;
/**
* Max queueing time in rate limiter behavior.
*/
private int maxQueueingTimeMs = 500;
private boolean clusterMode;
/**
* Flow rule config for cluster mode.
*/
private ClusterFlowConfig clusterConfig;
/**
* The traffic shaping (throttling) controller.
*/
private TrafficShapingController controller;
复制代码
一条限流规则主要由下面几个因素组成,咱们能够组合这些元素来实现不一样的限流效果:
FlowSlot是负责流量控制的功能插槽,具体实现以下:
* 流量规则检查器
*/
private final FlowRuleChecker checker;
public FlowSlot() {
this(new FlowRuleChecker());
}
...
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
boolean prioritized, Object... args) throws Throwable {
checkFlow(resourceWrapper, context, node, count, prioritized);
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
void checkFlow(ResourceWrapper resource, Context context, DefaultNode node, int count, boolean prioritized)
throws BlockException {
checker.checkFlow(ruleProvider, resource, context, node, count, prioritized);
}
/**
* 规则提供者
*/
private final Function<String, Collection<FlowRule>> ruleProvider = new Function<String, Collection<FlowRule>>() {
@Override
public Collection<FlowRule> apply(String resource) {
// Flow rule map should not be null.
Map<String, List<FlowRule>> flowRules = FlowRuleManager.getFlowRuleMap();
return flowRules.get(resource);
}
};
...
复制代码
FlowSLot中定义了一个FlowRuleChecker,FlowRuleChecker负责对限流规则进行检查。能够看到,FlowSlot实际的限流逻辑调用FlowRuleChecker实现的。在调用FlowRuleChecker的checkFlow()方法的时候,须要传入一个ruleProvider,这是一个Function。
上面说到FlowRuleChecker是负责流量控制校验的,FlowSlot中调用FlowRuleChecker的checkFlow()方法:
public void checkFlow(Function<String, Collection<FlowRule>> ruleProvider, ResourceWrapper resource,
Context context, DefaultNode node, int count, boolean prioritized) throws BlockException {
if (ruleProvider == null || resource == null) {
return;
}
Collection<FlowRule> rules = ruleProvider.apply(resource.getName());
if (rules != null) {
for (FlowRule rule : rules) {
if (!canPassCheck(rule, context, node, count, prioritized)) {
throw new FlowException(rule.getLimitApp(), rule);
}
}
}
}
复制代码
checkFlow()很简单,就是获取限流规则,遍历调用canPassCheck()方法进行校验,若是校验失败,则抛出FlowException。
public boolean canPassCheck(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node, int acquireCount,
boolean prioritized) {
String limitApp = rule.getLimitApp();
if (limitApp == null) {
return true;
}
if (rule.isClusterMode()) {
return passClusterCheck(rule, context, node, acquireCount, prioritized);
}
return passLocalCheck(rule, context, node, acquireCount, prioritized);
}
复制代码
canPassCheck()也很简单,就是根据不一样的模式调用不一样的方法。Sentinel可使用集群模式运行或者本地模式,不一样的模式限流逻辑不同。这个地方因为没有讲到集群,因此先按本地模式进行分析。
private static boolean passLocalCheck(FlowRule rule, Context context, DefaultNode node, int acquireCount,
boolean prioritized) {
Node selectedNode = selectNodeByRequesterAndStrategy(rule, context, node);
if (selectedNode == null) {
return true;
}
return rule.getRater().canPass(selectedNode, acquireCount, prioritized);
}
复制代码
passLocalCheck()中,先根据配置的strategy和请求来源,得到对应的Node节点,再调用对应节点的canPass()方法进行校验。
在FlowRule中有一个TrafficShapingController,表明流量控制的类型,包括默认值、直接拒绝、Warm Up、匀速排队,因此具体如何限流须要看设置的策略。
TrafficShapingController是一个接口,主要是定义流量控制策略,它有三个实现,分别表明不一样的处理模式:
在FlowRule中会有一个TrafficShapingController类型的变量rater,这个rater是在更新规则的时候根据设置的规则建立出来的,具体以下:
private static TrafficShapingController generateRater(/*@Valid*/ FlowRule rule) {
if (rule.getGrade() == RuleConstant.FLOW_GRADE_QPS) {
switch (rule.getControlBehavior()) {
case RuleConstant.CONTROL_BEHAVIOR_WARM_UP:
return new WarmUpController(rule.getCount(), rule.getWarmUpPeriodSec(),
ColdFactorProperty.coldFactor);
case RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER:
return new RateLimiterController(rule.getMaxQueueingTimeMs(), rule.getCount());
case RuleConstant.CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER:
return new WarmUpRateLimiterController(rule.getCount(), rule.getWarmUpPeriodSec(),
rule.getMaxQueueingTimeMs(), ColdFactorProperty.coldFactor);
case RuleConstant.CONTROL_BEHAVIOR_DEFAULT:
default:
// Default mode or unknown mode: default traffic shaping controller (fast-reject).
}
}
return new DefaultController(rule.getCount(), rule.getGrade());
}
复制代码
Sentinel熔断降级会在调用链路中某个资源出现不稳定状态的时候对该资源进行限制,让请求快速失败,避免影响其余的资源而致使级联错误。当资源被降级后,在接下来的降级时间窗口内,对该资源的调用都会自动熔断。
平均响应时间 (DEGRADE_GRADE_RT):当 1s 内持续进入 5 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)以内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算做 4900 ms,若须要变动此上限能够经过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。
异常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量 >= 5,而且每秒异常总数占经过量的比值超过阈值(DegradeRule 中的 count)以后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)以内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],表明 0% - 100%。
异常数 (DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数目超过阈值以后会进行熔断。注意因为统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态
public class DegradeRule extends AbstractRule {
/**
* 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, 2: exception count).
*/
private int grade = RuleConstant.DEGRADE_GRADE_RT;
/**
* 每秒钟连续进入的请求超的平均响应时间超过阀值的请求数
* Minimum number of consecutive slow requests that can trigger RT circuit breaking.
*
* @since 1.7.0
*/
private int rtSlowRequestAmount = RuleConstant.DEGRADE_DEFAULT_SLOW_REQUEST_AMOUNT;
/**
* 每秒钟连续进入的请求发生异常的请求数
* Minimum number of requests (in an active statistic time span) that can trigger circuit breaking.
*
* @since 1.7.0
*/
private int minRequestAmount = RuleConstant.DEGRADE_DEFAULT_MIN_REQUEST_AMOUNT;
}
复制代码
DeGradeRule表明熔断降级的规则,各个字段含义为:
DegradeSlot是负责处理熔断降级的功能插槽,其代码很是简单,由于具体熔断降级的判断是在DegradeRuleManager中实现的。
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);
}
复制代码
DegradeRuleManager主要负责加载熔断降级规则、对调用entry进行熔断降级校验。
/**
* 保存降级规则的缓存,以resource为key
*/
private static final Map<String, Set<DegradeRule>> degradeRules = new ConcurrentHashMap<>();
/**
* 规则改变处理器
*/
private static final RulePropertyListener LISTENER = new RulePropertyListener();
private static SentinelProperty<List<DegradeRule>> currentProperty
= new DynamicSentinelProperty<>();
static {
currentProperty.addListener(LISTENER);
}
复制代码
DegradeRuleManager使用一个map来保存不一样资源加载的熔断降级规则,而且也拥有本身的规则改变处理器,规则的加载和更新逻辑与其余功能插槽相似。
从上面能够看出,当entry进入DegradeSlot的时候,其实是调用DegradeRuleManager的checkDegrade()方法进行熔断降级的检查。
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) {
if (!rule.passCheck(context, node, count)) {
throw new DegradeException(rule.getLimitApp(), rule);
}
}
}
复制代码
checkDegrade()方法先根据resource获取对应的限流规则,而后循环调用规则的passCheck()方法进行检查,若是不能经过检查,则抛出DegradeException。
因此,具体的校验逻辑是在DegradeRule中的passCheck()实现的,具体代码以下:
public boolean passCheck(Context context, DefaultNode node, int acquireCount, Object... args) {
//若是是在限流的窗口时间内,直接降级
if (cut.get()) {
return false;
}
//降级只针对resource维度进行,不区分context,不区分orgin,在statisticSlot中会在defaultNode里面对clusterNode进行累加
ClusterNode clusterNode = ClusterBuilderSlot.getClusterNode(this.getResource());
if (clusterNode == null) {
return true;
}
if (grade == RuleConstant.DEGRADE_GRADE_RT) {
//case1: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) {
//case2 异常比例
double exception = clusterNode.exceptionQps();
double success = clusterNode.successQps();
double total = clusterNode.totalQps();
//若是请求总数小于设置的每秒容许的最小请求数量,直接返回
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) {
//case3: 异常数
//统计异常总数的时间窗口是分钟级别的,若是timeWindow的时间小于60s,会以60s进行熔断
double exception = clusterNode.totalException();
//若是异常数小于指定的值,直接返回
if (exception < count) {
return true;
}
}
//开启一个定时任务,在指定的窗口时间后执行,将请求数设置为0,降级标识设置为false
if (cut.compareAndSet(false, true)) {
ResetTask resetTask = new ResetTask(this);
pool.schedule(resetTask, timeWindow, TimeUnit.SECONDS);
}
return false;
}
复制代码
passCheck()逻辑比较简单,主要是先根据以前获取的数据判断是否知足降级设置的阈值,若是超过,则返回false,而且开启一个线程,其做用就是发生降级后指定的timeWindow内直接将后续请求当作降级处理。
这篇文章主要分析Sentinel中经常使用的功能插槽的实现原理,了解Sentinel的限流降级策略。