Spring Cloud Alibaba Sentinel 源码分析-滑动时间窗口算法原理

“滑动时间窗口算法” 是Sentinel源码中的一个非常重要的算法。

image-20211222170933011

时间窗算法

那么在了解滑动时间窗算法之前,我们先要来了解时间窗算法,也可以称之为:固定时间窗算法

概念:固定时间窗口计数器算法思想:在固定的时间窗口内,可以允许固定数量的请求进入。超过数量就拒绝或者排队,等下一个时间段进入。

阅读更多

Spring Cloud Alibaba Sentinel DegradeSlot 源码解析

DegradeSlot是熔断降级的Slot,那我们直接来看核心方法

1
2
3
4
5
6
7
8
9
//DegradeSlot.entry
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
boolean prioritized, Object... args) throws Throwable {
// 熔断降级检测
performChecking(context, resourceWrapper);
// 触发下一个节点
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
阅读更多

Spring Cloud Alibaba Sentinel StatisticSlot 源码解析

StatisticSlot定义:

StatisticSlot 是 Sentinel 最为重要的类之一,用于根据规则判断结果进行相应的统计操作。

entry 的时候:依次执行后面的判断 slot。每个 slot 触发流控的话会抛出异常(BlockException的子类)。若有 BlockException抛出,则记录 block 数据;若无异常抛出则算作可通过(pass),记录 pass 数据。

exit 的时候:若无 error(无论是业务异常还是流控异常),记录 complete(success)以及 RT,线程数-1。

阅读更多

Spring Cloud Alibaba Sentinel FlowSlot 源码解析

FlowSlot获取全部流控规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 获取到指定资源的所有流控规则
Collection<FlowRule> rules = ruleProvider.apply(resource.getName());
// 逐个应用流控规则。若无法通过则抛出异常,后续规则不再应用
if (rules != null) {
for (FlowRule rule : rules) {
if (!canPassCheck(rule, context, node, count, prioritized)) {
// FlowException继承BlockException
throw new FlowException(rule.getLimitApp(), rule);
}
}
}
-------------------------------------------------------------------------------------------
// 这里调用的apply方法就是FlowSlot中的对应方法
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.
// 获取所有资源和对应的流控规则 key为资源名称,value为该资源对应的所有流控规则
Map<String, List<FlowRule>> flowRules = FlowRuleManager.getFlowRuleMap();
// 获取指定资源的流控规则
return flowRules.get(resource);
}
};
阅读更多

Spring Cloud Alibaba Sentinel 源码解析 SlotChain 入口解析

arch overview

默认Chain解析

​ 我们从这里继续分析,这个位置的chain.entry方法,但是此时这个chain是谁?

1
2
3
4
5
6
7
8
9
10
11
//CtSph中
try {
// 针对资源操作
chain.entry(context, resourceWrapper, null, count, prioritized, args);
} catch (BlockException e1) {
e.exit(count, args);
throw e1;
} catch (Throwable e1) {
// This should not happen, unless there are errors existing in Sentinel internal.
RecordLog.info("Sentinel unexpected exception", e1);
}
阅读更多

Spring Cloud Alibaba Sentinel 源码解析 ClusterBuilderSlot 解析

官方定义

ClusterBuilderSlot:则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//NodeSelectorSlot.entry()
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args)
throws Throwable {
// 从缓存中获取,创建DefaultNode
DefaultNode node = map.get(context.getName());
// 双重判断,如果判断为空
if (node == null) {
synchronized (this) {
node = map.get(context.getName());
if (node == null) {
// 创建一个DefaultNode并且放入到缓存中
node = new DefaultNode(resourceWrapper, null);
HashMap<String, DefaultNode> cacheMap = new HashMap<String, DefaultNode>(map.size());
cacheMap.putAll(map);
cacheMap.put(context.getName(), node);
map = cacheMap;
// Build invocation tree
// 将新建的Node添加到调用树中
((DefaultNode) context.getLastNode()).addChild(node);
}

}
}

context.setCurNode(node);
// 触发下一个节点
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
阅读更多

Spring Cloud Alibaba Sentinel 源码解析 构建 Context

我们继续分析当前这个类型中的InternalContextUtil.internalEnter(Constants.CONTEXT_DEFAULT_NAME);方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* This class is used for skip context name checking.
此类型是用于跳过Context名称的检测
*/
private final static class InternalContextUtil extends ContextUtil {
static Context internalEnter(String name) {
// 从这里继续跟踪
return trueEnter(name, "");
}

static Context internalEnter(String name, String origin) {
return trueEnter(name, origin);
}
}
阅读更多