寻找一把进入 Alibaba Sentinel 的钥匙(文末附流程图)

context = InternalContextUtil.internalEnter(Constants.CONTEXT_DEFAULT_NAME);

}

if (!Constants.ON) { // @3

return new CtEntry(resourceWrapper, null, context);

}

ProcessorSlot chain = lookProcessChain(resourceWrapper); // @4

if (chain == null) {

return new CtEntry(resourceWrapper, null, context);

}

Entry e = new CtEntry(resourceWrapper, chain, context); // @5

try {

chain.entry(context, resourceWrapper, null, count, prioritized, args); // @6

} catch (BlockException e1) { // @7

e.exit(count, args);

throw e1;

} catch (Throwable e1) {

RecordLog.info(“Sentinel unexpected exception”, e1);

}

return e;

}

代码@1:我们先来介绍一下该方法的参数:

  • ResourceWrapper resourceWrapper

资源的包装类型,可以是字符串类型的资源描述,也可以是方法类的。

  • int count

此次需要消耗的令牌。

  • boolean prioritized

是否注重优先级。

  • Object… args

额外参数。

代码@2:获取方法调用的上下文环境,上下环境对象存储在线程本地变量:ThreadLocal 中,这里先“剧透”一下,上下文环境中存储的是整个调用链,后续文章会重点介绍。

代码@3:Sentinel 提供一个全局关闭的开关,如果关闭,返回的 CtEntry 中的 chain 为空,从这里可以看出,如果 chain 为空,则不会触发 Sentinel 流控相关的逻辑,从侧面也反应了该属性的重要性。

代码@4:为该资源加载处理链链,这里是最最重要的方法,将在下文详细介绍。

代码@5:根据资源ID、处理器链、上下文环境构建 CtEntry 对象。

代码@6:调用 chain 的 entry 方法。

代码@7:如果出现 BlockException ,调用 CtEntry 的 exit 方法。

2、Sentienl ProcessorSlot 处理链


我们接下来重点看一下 lookProcessChain 方法的实现细节。

CtSph#lookProcessChain

ProcessorSlot lookProcessChain(ResourceWrapper resourceWrapper) {

ProcessorSlotChain chain = chainMap.get(resourceWrapper); // @1

if (chain == null) {

synchronized (LOCK) {

chain = chainMap.get(resourceWrapper);

if (chain == null) {

// Entry size limit.

if (chainMap.size() >= Constants.MAX_SLOT_CHAIN_SIZE) { // @2

return null;

}

chain = SlotChainProvider.newSlotChain(); // @3

Map<ResourceWrapper, ProcessorSlotChain> newMap = new HashMap<ResourceWrapper, ProcessorSlotChain>(

chainMap.size() + 1);

newMap.putAll(chainMap);

newMap.put(resourceWrapper, chain);

chainMap = newMap;

}

}

}

return chain;

}

代码@1:chainMap 一个全局的缓存表,即同一个资源 ResourceWrapper (同一个资源名称) 会共同使用同一个 ProcessorSlotChain ,即不同的线程在访问同一个资源保护的代码时,这些线程将共同使用 ProcessorSlotChain 中的各个 ProcessorSlot 。注意留意 ResourceWrapper 的 equals 方法与 hashCode 方法。

代码@2:这里重点想突出,如果同时在进入的资源个数超过 MAX_SLOT_CHAIN_SIZE,默认为 6000,会返回 null,则不对本次请求执行限流,熔断计算,而是直接跳过,这个点还是值得我们注意的。

代码@3:通过 SlotChainProvider 创建对应的处理链。

SlotChainProvider#newSlotChain

public static ProcessorSlotChain newSlotChain() {

if (slotChainBuilder != null) { // @1

return slotChainBuilder.build();

}

slotChainBuilder = SpiLoader.loadFirstInstanceOrDefault(SlotChainBuilder.class, DefaultSlotChainBuilder.class); // @2

if (slotChainBuilder == null) { // @3

RecordLog.warn(“[SlotChainProvider] Wrong state when resolving slot chain builder, using default”);

slotChainBuilder = new DefaultSlotChainBuilder();

} else {

RecordLog.info("[SlotChainProvider] Global slot chain builder resolved: "

  • slotChainBuilder.getClass().getCanonicalName());

}

return slotChainBuilder.build(); // @4

}

代码@1:如果 slotChainBuilder 不为空,则直接调用其 build 方法构建处理器链。

代码@2:如果为空,首先通过 JAVA 的 SPI 机制,尝试加载自定义的 Slot Chain 构建器实现类。如果需要实现自定义的 Chain 构建器,只需实现 SlotChainBuilder 接口,然后将其放在 classpath 下即可,如果存在多个,以找到的第一个为准。

代码@3:如果从 SPI 机制中加载失败,则使用默认的构建器:DefaultSlotChainBuilder。

代码@4:调用其 build 方法构造 Slot Chain。

那接下来我们先来看看 Sentinel 的 SlotChainBuilder 类体系,然后看看 DefaultSlotChainBuilder 的 build 方法。

2.1 SlotChainBuilder 类体系

在这里插入图片描述

主要有三个实现类,对应热点、接口网关以及普通场景。我们接下来将重点介绍 DefaultSlotChainBuilder ,关于热点限流与网关限流将在后面的文章中详细探讨。

2.2 DefaultSlotChainBuilder build 方法

DefaultSlotChainBuilder#build

public class DefaultSlotChainBuilder implements SlotChainBuilder {

public ProcessorSlotChain build() {

ProcessorSlotChain chain = new DefaultProcessorSlotChain();

chain.addLast(new NodeSelectorSlot());

chain.addLast(new ClusterBuilderSlot());

chain.addLast(new LogSlot());

chain.addLast(new StatisticSlot());

chain.addLast(new AuthoritySlot());

chain.addLast(new SystemSlot());

chain.addLast(new FlowSlot());

chain.addLast(new DegradeSlot());

return chain;

}

}

就问大家激不激动,开不开心,从这些 Slot 的名字基本就能得出其含义。

  • NodeSelectorSlot

主要用于构建调用链。

  • ClusterBuilderSlot

用于集群限流、熔断。

  • LogSlot

用于记录日志。

  • StatisticSlot

用于实时收集实时消息。

  • AuthoritySlot

用于权限校验的。

  • SystemSlot

用于验证系统级别的规则。

  • FlowSlot

实现限流机制。

  • DegradeSlot

实现熔断机制。

经过上面的方法,就构建一条 Slot 处理链。其实到这里我们就不难发现,调用 ProcessorSlotChain 的 entry 方法,就是依次调用这些 slot 的方法。关于 ProcessorSlotChain 的类层次结构就不再多说明了,其实现比较简单,大家如果有兴趣的话,可以关注这部分的实现,这里代表一类场景:一对多、责任链的设计模式。

3、Sentinel SphU.entry 处理流程图


经过上面的探索,我们其实已经找到了 Sentinel 的关于限流、熔断核心处理逻辑的入口,就是 FlowSlot、DegradeSlot。接下来我们以一张流程图来结束本文的讲解。

在这里插入图片描述

本文的目的就是打开 Sentinel 的大门,即寻找实时数据收集、限流、熔断实现机制的入口,从而正式探寻 Sentienl 的核心实现原理,更多精彩请继续期待该专栏的后续内容。

点赞是一种美德,如果觉得本文写的不错的话,还请帮忙点个赞,您的认可是我持续创造的最大动力,谢谢。


欢迎加笔者微信号(dingwpmz),加群探讨,笔者优质专栏目录:

1、源码分析RocketMQ专栏(40篇+)

2、源码分析Sentinel专栏(12篇+)

3、源码分析Dubbo专栏(28篇+)

4、源码分析Mybatis专栏

5、源码分析Netty专栏(18篇+)
6、源码分析JUC专栏
7、源码分析Elasticjob专栏
8、Elasticsearch专栏(20篇+)
9、源码分析MyCat专栏
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

我还通过一些渠道整理了一些大厂真实面试主要有:蚂蚁金服、拼多多、阿里云、百度、唯品会、携程、丰巢科技、乐信、软通动力、OPPO、银盛支付、中国平安等初,中级,高级Java面试题集合,附带超详细答案,希望能帮助到大家。

新鲜出炉的蚂蚁金服面经,熬夜整理出来的答案,已有千人收藏

还有专门针对JVM、SPringBoot、SpringCloud、数据库、Linux、缓存、消息中间件、源码等相关面试题。

新鲜出炉的蚂蚁金服面经,熬夜整理出来的答案,已有千人收藏

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
我还通过一些渠道整理了一些大厂真实面试主要有:蚂蚁金服、拼多多、阿里云、百度、唯品会、携程、丰巢科技、乐信、软通动力、OPPO、银盛支付、中国平安等初,中级,高级Java面试题集合,附带超详细答案,希望能帮助到大家。

[外链图片转存中…(img-0W6ZWD7k-1713659786006)]

还有专门针对JVM、SPringBoot、SpringCloud、数据库、Linux、缓存、消息中间件、源码等相关面试题。

[外链图片转存中…(img-Tbc45mOm-1713659786006)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值