下载地址:
文本预览:
作者 | 一起撸Java
来源 |今日头条
**学习目标**
* Sentinel的工作原理
**第1章 限流原理**
在Sentinel中,所有的资源都对应一个资源名称以及一个Entry。每一个entry可以表示一个请求。而Sentinel中,会针对当前请求基于规则的判断来实现流控的控制,原理如下图所示。
上图仅作为设计思想的展示,图中 Slot 的顺序已和最新版 Sentinel Slot Chain 顺序不一致
当一个外部请求过来之后,会创建一个Entry,而创建Entry的同时,也会创建一系列的slot 组成一个责任链,每个slot有不同的工作职责。
* NodeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;
* ClusterBuilderSlot 则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS,thread count 等等,这些信息将用作为多维度限流,降级的依据;
* StatisticSlot 则用于记录、统计不同纬度的 runtime 指标监控信息;
* FlowSlot 则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;
* AuthoritySlot 则根据配置的黑白名单和调用来源信息,来做黑白名单控制;
* DegradeSlot 则通过统计信息以及预设的规则,来做熔断降级;
* SystemSlot 则通过系统的状态,例如 load1 等,来控制总的入口流量;
* LogSlot 在出现限流、熔断、系统保护时负责记录日志
* ...
Sentinel 将 ProcessorSlot 作为 SPI 接口进行扩展(1.7.2 版本以前 SlotChainBuilder 作为SPI),使得 Slot Chain 具备了扩展的能力。您可以自行加入自定义的 slot 并编排 slot 间的顺序,从而可以给 Sentinel 添加自定义的功能。
**Spring Cloud 集成Sentinel的原理**
Spring Cloud 中集成Sentinel限流,是基于拦截器来实现,具体的实现路径如下。
SentinelWebAutoConfiguration——>addInterceptors——>SentinelWebInterceptor->AbstractSentinelInterceptor
```
public boolean preHandle(HttpServletRequest request, HttpServletResponseresponse, Object handler) throws Exception { try { String resourceName = this.getResourceName(request); if (StringUtil.isEmpty(resourceName)) { return true; } else if (this.increaseReferece(request,this.baseWebMvcConfig.getRequestRefName(), 1) != 1) { return true; } else { String origin = this.parseOrigin(request); String contextName = this.getContextName(request); ContextUtil.enter(contextName, origin); Entry entry = SphU.entry(resourceName, 1, EntryType.IN); request.setAttribute(this.baseWebMvcConfig.getRequestAttributeName(), entry); return true; } } catch (BlockException var12) { BlockException e = var12; try { this.handleBlockException(request, response, e); } finally { ContextUtil.exit(); } return false; }}
```
> 资源调用的流量类型,是入口流量( EntryType.IN )还是出口流量( EntryType.OUT ),注意系统规则只对 IN 生效
**第2章 SphU.entry**
不管是集成dubbo也好,还是集成到spring cloud中也好,最终都是调用SphU.entry这个方法来进行限流判断的,接下来我们从SphU.entry这个方法中去了解它的实现原理。
代码中我们可能唯一疑惑的,也是最关键的一步是 SphU.entry(resource) , 我们传进去了一个资源,这个资源可用是方法名,可以是接口,那么他具体做了什么呢?让我们来一步步揭开他的神秘面纱:
```
public static Entry entry(String name) throws BlockException { return Env.sph.entry(name, EntryType.OUT, 1, OBJECTS0);}public class Env { public static final Sph sph = new CtSph(); ......//省略部分代码}
```
从 SphU.entry() 方法往下执行会进入到 Sph.entry() ,Sph的默认实现类是 CtSph,而最终会进入CtSph 的entry 方法:
```
@Overridepublic Entry entry(String name, EntryType type, int count, Object... args) throws BlockException { //封装了一个资源对象 StringResourceWrapper resource = new StringResourceWrapper(name, type); return entry(resource, count, args);}
```
这里的主要步骤是通过我们给定的资源去封装了一个 StringResourceWrapper ,然后传入自己的重载方法,继而调用 entryWithPriority(resourceWrapper, count, false, args):
* ResourceWrapper 表示sentinel的资源,做了封装
* count表示本次请求的占用的并发数量,默认是1
* prioritized,优先级
```
private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count,boolean prioritized, Object... args) throws BlockException { //获取上下文环境,存储在ThreadLocal中,context中会存储整个调用链 Context context = ContextUtil.getContext(); //如果是 NullContext,那么说明 context name 超过了 2000 个,参见 ContextUtil#trueEnter //这个时候,Sentinel 不再接受处理新的 context 配置,也就是不做这些新的接口的统计、限流熔断等 if (context instanceof NullContext) { // The {@link NullContext} indicates that the amount of context has exceeded the threshold, // so here init the entry only. No rule checking will be done. return new CtEntry(resourceWrapper, null, context); } if (context == null) {//使用默认context // 生成Context的部分 context = InternalContextUtil.internalEnter(Constants.CONTEXT_DEFAULT_NAME); } // Global switch is close, no rule checking will do. if (!Constants.ON) {//全局限流开关是否已经开启,如果关闭了,就不进行限流规则检查 return new CtEntry(resourceWrapper, null, context); } //设计模式中的责任链模式。 //构建一个slot链表 ProcessorSlot