Sentinel源码解析-请求入口

文章目录

  • 一、Sentinel架构
  • 二、@SentinelResouce处理流程
    • 1. SentinelResourceAspect-入口
      • 1.1 getResourceName(获取资源名)
      • 1.2 SphU#entry(核心增强逻辑)
        • 1.2.1. Env
        • 1.2.2. InitExecutor#doInit
        • 1.2.3.InitFunc实现类
        • 1.2.4. entryWithType
        • 1.2.5 entryWithPriority
          • 1.2.5.1 ContextUtil#getContext
          • 1.2.5.2 ContextUtil#initDefaultContext
          • 1.2.5.3 Tree、Node、Context的关系
          • 1.2.5.4 InternalContextUtil#internalEnter
          • 1.2.5.5 SlotChainProvider#newSlotChain
          • 1.2.5.6 CtSph#lookProcessChain(构造处理链)
          • 1.2.5.6 DefaultSlotChainBuilder#build
          • 1.2.5.7 DefaultProcessorSlotChain#entry


一、Sentinel架构

Sentinel源码解析-请求入口_第1张图片
从上述架构图中可以看出Sentinlel的核心就是一个处理链,一次请求过来会经过处理链上的多个slot处理,来进行熔断降级,流控等核心功能,对应每个slot的具体实现我们在后续会逐一进行讲解。

二、@SentinelResouce处理流程

1. SentinelResourceAspect-入口

在上篇源码环境搭建的时候我们通过在方法上标注@SentinelResouce注解来表示这个是sentinel的一个资源,然后就在sentinel- dashboard上面配置对应的流控规则来实现限流逻辑。注解的处理逻辑是在SentinelResourceAspect这个切面中进行处理

Sentinel源码解析-请求入口_第2张图片

1.1 getResourceName(获取资源名)

这里首先判断注解中有没有指定资源名,如果指定了资源名就用注解指定的,如果没有指定资源名,则通过解析方法,通过通过方法所在类+方法名+方法参数类名拼接出来一个资源名

Sentinel源码解析-请求入口_第3张图片

1.2 SphU#entry(核心增强逻辑)

这里会真正调用EnvsphentryWithType来执行真正处理逻辑。

在这里插入图片描述

1.2.1. Env

这里我们发现:

  1. sph的一个具体实现是CtSph
  2. Env的静态代码块中会调用InitExecutor#doInit方法

Sentinel源码解析-请求入口_第4张图片

1.2.2. InitExecutor#doInit

initExecutor#doinit方法中会去加载初始化组件,会通过spi加载对应的初始化组件,找到InitFunc的实现类,并排序进行初始化操作。

Sentinel源码解析-请求入口_第5张图片

1.2.3.InitFunc实现类

这里看好像是环境的初始化操作,初始化需要的对应组件,不是主线逻辑,我们在Env中已经知道sph的具体实现是CtSph,我们继续追踪下CtSph#entryWithType方法。

Sentinel源码解析-请求入口_第6张图片

1.2.4. entryWithType

  1. 这里把name,entryType和ResourceType包装成一个ResourceWrapper
  2. 继续调用entryWithPriority方法

Sentinel源码解析-请求入口_第7张图片

1.2.5 entryWithPriority

  1. 首先会给当前线程绑定一个context
  2. 查找对应的slotChain,也就是对应对这个资源的一个处理链
  3. 调用chain#entry方法对资源进行过处理链的操作

Sentinel源码解析-请求入口_第8张图片

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

Sentinel源码解析-请求入口_第9张图片

1.2.5.3 Tree、Node、Context的关系

首先是这个Tree,这个Tree是由NodeSelectorSlot这个插槽来创建的,每创建一个树都有一个Root节点,这个Root节点就代表的是一个应用,一个应用只会创建一个Root节点。就比如说一个一个dubbo项目中会有provider和consumer,这一个consumer就是一个应用。

在这里插入图片描述

一个应用中可以定义很多资源可以是代码块、方法等等:

Sentinel源码解析-请求入口_第10张图片

当属于同一个应用下的请求过来后,会首先判断是否有Root,没有的话就会新建一个Root节点。
再往下就会出现EntranceNodeDefaultNodeCLusterNode三种node,那这三种节点又是什么关系呢?我们首先看一下这三个节点类的关系图:

其中StatsticNode是用作数据统计的,那根据继承关系其三个子类Node也是进行数据统计,那他们分别的作用又是什么呢?
在讲这三个Node前,大家要明白Sentinel的一个核心概念Context
Context是对资源操作的上下文,每个资源操作必须属于一个Context。它会保存一次资源访问链路元数据和该资源所对应的实时信息,链路的各个节点都能通过获取链路绑定的context来获取一些信息进行相应的处理。如果代码中没有指定Context,则会创建一个namesentinel_default_context的默认Context。一个Context生命周期中可以包含多个资源操作。Context生命周期中的最后一个资源在exit()时会清理该Conetxt,这也就意味着这个Context生命周期结束了。

Sentinel源码解析-请求入口_第11张图片

Node:用于完成数据统计的接口
StatisticNode:统计节点,是Node接口的实现类,用于完成数据统计
EntranceNode:入口节点,一个Context会有一个入口节点,用于统计当前Context的总体流量数据
DefaultNode:默认节点,用于统计一个资源在当前Context中的流量数据
ClusterNode:集群节点,用于统计一个资源在所有Context中的总体流量数据

Sentinel源码解析-请求入口_第12张图片

1.2.5.4 InternalContextUtil#internalEnter

如果发现当前请求线程如果没有绑定context,则给当前线程绑定一个名为sentinel_default_contextcontext

Sentinel源码解析-请求入口_第13张图片

1.2.5.5 SlotChainProvider#newSlotChain
  1. 首先根据当前资源从缓存中获取处理链
  2. 没有获取到则调用SlotChainProvider#newSlotChain构造处理链

Sentinel源码解析-请求入口_第14张图片

1.2.5.6 CtSph#lookProcessChain(构造处理链)
  1. 这里首先通过SPI方式创建builder,如果你没有指定则会创建一个DefaultSlotChainBuilder

Sentinel源码解析-请求入口_第15张图片

1.2.5.6 DefaultSlotChainBuilder#build
  1. 这里会创建一个ProcessorSlotChain
  2. 通过SPI机制获取对应的处理链中的slot,这里会去sentinel-core/src/main/resources/META-INF/services找对应的Slot然后进行初始化
  3. slot添加到处理链中

Sentinel源码解析-请求入口_第16张图片
Sentinel源码解析-请求入口_第17张图片

1.2.5.7 DefaultProcessorSlotChain#entry

这里会调用到处理链中的具体的slot,每个slot的具体实现我们后续文章继续分析。

在这里插入图片描述

你可能感兴趣的:(sentinel源码解析,sentinel,java)