文章目录
一、Sentinel架构
从上述架构图中可以看出Sentinlel
的核心就是一个处理链,一次请求过来会经过处理链上的多个slot
处理,来进行熔断降级,流控等核心功能,对应每个slot
的具体实现我们在后续会逐一进行讲解。
二、@SentinelResouce处理流程
1. SentinelResourceAspect-入口
在上篇源码环境搭建的时候我们通过在方法上标注
@SentinelResouce
注解来表示这个是sentinel
的一个资源,然后就在sentinel- dashboard
上面配置对应的流控规则来实现限流逻辑。注解的处理逻辑是在SentinelResourceAspect
这个切面中进行处理
1.1 getResourceName(获取资源名)
这里首先判断注解中有没有指定资源名,如果指定了资源名就用注解指定的,如果没有指定资源名,则通过解析方法,通过通过方法所在类+方法名+方法参数类名拼接出来一个资源名
1.2 SphU#entry(核心增强逻辑)
这里会真正调用
Env
的sph
的entryWithType
来执行真正处理逻辑。
1.2.1. Env
这里我们发现:
sph
的一个具体实现是CtSph
- 在
Env
的静态代码块中会调用InitExecutor#doInit
方法
1.2.2. InitExecutor#doInit
在
initExecutor#doinit
方法中会去加载初始化组件,会通过spi
加载对应的初始化组件,找到InitFunc
的实现类,并排序进行初始化操作。
1.2.3.InitFunc实现类
这里看好像是环境的初始化操作,初始化需要的对应组件,不是主线逻辑,我们在Env中已经知道
sph
的具体实现是CtSph
,我们继续追踪下CtSph#entryWithType
方法。
1.2.4. entryWithType
- 这里把
name,entryType和ResourceType
包装成一个ResourceWrapper
- 继续调用
entryWithPriority
方法
1.2.5 entryWithPriority
- 首先会给当前线程绑定一个context
- 查找对应的slotChain,也就是对应对这个资源的一个处理链
- 调用chain#entry方法对资源进行过处理链的操作
1.2.5.1 ContextUtil#getContext
这里会调用
contextHolder#get
方法,contextHolder
是一个ThreadLocal
,如果从ThreadLocal
中没有获取到当前线程的context
,则后续会调用InternalContextUtil#internalEnter方
法初始化一个context
放进来
1.2.5.2 ContextUtil#initDefaultContext
这里我们看到
ContextUtil
的静态代码块中会调用initDefaultContext
方法来初始化默认的上下问,首先通过Constants.ROOT
创建一个root
节点,然将新创建的Node
节点加入到root
的字节点中,并存入contextNameNodeMap
中
1.2.5.3 Tree、Node、Context的关系
首先是这个Tree,这个Tree是由NodeSelectorSlot这个插槽来创建的,每创建一个树都有一个Root节点,这个Root节点就代表的是一个应用,一个应用只会创建一个Root节点。就比如说一个一个dubbo项目中会有provider和consumer,这一个consumer就是一个应用。
一个应用中可以定义很多资源可以是代码块、方法等等:
当属于同一个应用下的请求过来后,会首先判断是否有
Root
,没有的话就会新建一个Root
节点。
再往下就会出现EntranceNode
、DefaultNode
、CLusterNode
三种node
,那这三种节点又是什么关系呢?我们首先看一下这三个节点类的关系图:其中
StatsticNode
是用作数据统计的,那根据继承关系其三个子类Node
也是进行数据统计,那他们分别的作用又是什么呢?
在讲这三个Node
前,大家要明白Sentinel
的一个核心概念Context
:
Context
是对资源操作的上下文,每个资源操作必须属于一个Context
。它会保存一次资源访问链路元数据和该资源所对应的实时信息,链路的各个节点都能通过获取链路绑定的context
来获取一些信息进行相应的处理。如果代码中没有指定Context
,则会创建一个name
为sentinel_default_context
的默认Context
。一个Context
生命周期中可以包含多个资源操作。Context
生命周期中的最后一个资源在exit()
时会清理该Conetxt
,这也就意味着这个Context
生命周期结束了。
Node
:用于完成数据统计的接口
StatisticNode
:统计节点,是Node接口的实现类,用于完成数据统计
EntranceNode
:入口节点,一个Context会有一个入口节点,用于统计当前Context的总体流量数据
DefaultNode
:默认节点,用于统计一个资源在当前Context中的流量数据
ClusterNode
:集群节点,用于统计一个资源在所有Context中的总体流量数据
1.2.5.4 InternalContextUtil#internalEnter
如果发现当前请求线程如果没有绑定
context
,则给当前线程绑定一个名为sentinel_default_context
的context
1.2.5.5 SlotChainProvider#newSlotChain
- 首先根据当前资源从缓存中获取处理链
- 没有获取到则调用
SlotChainProvider#newSlotChain
构造处理链
1.2.5.6 CtSph#lookProcessChain(构造处理链)
- 这里首先通过
SPI方
式创建builder
,如果你没有指定则会创建一个DefaultSlotChainBuilder
。
1.2.5.6 DefaultSlotChainBuilder#build
- 这里会创建一个
ProcessorSlotChain
- 通过
SPI
机制获取对应的处理链中的slot
,这里会去sentinel-core/src/main/resources/META-INF/services
找对应的Slot
然后进行初始化- 把
slot
添加到处理链中
1.2.5.7 DefaultProcessorSlotChain#entry
这里会调用到处理链中的具体的
slot
,每个slot
的具体实现我们后续文章继续分析。