Sentinel原理

Sentinel是一个Java微服务的流量控制组件,其核心概念包括资源(Resource)、槽(Slot)、上下文(Context)、节点(Node)和度量(Metric)。资源是 Sentinel 的保护对象,通过资源定义来实现限流、降级等。Slot 构成调用链,每个 Slot 有特定职责,如 NodeSelectorSlot 构建调用树,FlowSlot 进行限流判断。上下文 Context 记录调用链的元数据,而 Node 保存资源的实时统计数据。Sentinel 使用滑动窗口进行数据统计,注解 SentinelResource 支持注解式资源定义。此外,Sentinel 提供适配器,如 dubbo-adapter,通过 Filter 拦截请求实现限流降级。
摘要由CSDN通过智能技术生成

1、核心概念

1.1、资源-Resource

  • Resource:Sentinel中最核心的概念,其通过资源来保护具体的业务代码或其他后方服务,用户只需要将代码或者服务定义为一个资源,然后再定义规则就可以了,剩下的交给sentinel来处理。并且资源和规则时解耦的,规则可在运行是动态修改;定义完资源后,就可以通过在程序中埋点来保护你自己的服务了,埋点的方式有两种:
    • try…catch的方式【通过 SphU.entry(...)】:当catch到BlockException时,执行异常处理或者fallback。
    • if…else的方式【通过 SphO.entry(...)】:当返回false时执行异常处理或者fallback。其实内部是将ry…catch的方式抛出的异常BlockException进行包装,有异常返回false。
//SphO.entry(...)
public static boolean entry(String name, EntryType type, int count, Object... args) {
   
    try {
   
        Env.sph.entry(name, type, count, args);
    } catch (BlockException e) {
   
        return false;
    } catch (Throwable e) {
   
        RecordLog.info("[Sentinel] Fatal error", e);
        return true;
    }
    return true;
}

//SphU.entry(...)
 public static Entry entry(String name, EntryType type, int count, Object... args) throws BlockException {
   
    return Env.sph.entry(name, type, count, args);
 }
  • 用户采用Sph…的方式定义资源对业务代码侵入很大,所以Sentinel提供了注解式【SentinelResource**】**来定义资源,并定义资源对应异常处理blockHandler

  • Sentinel中资源对应的类为ResourceWrapper,其为抽象的包装类,包装了资源的 Name 和**EntryType,**具体有两个实现类,分别是:StringResourceWrapper 和 MethodResourceWrapper``。

ResourceWrapper.png

  • StringResourceWrapper:是对String对一串字符串进行包装,是一个通用的资源包装类。
  • MethodResourceWrapper: 是对方法调用的包装。

1.2、槽-Slot

Sentinel的工作流程是围绕着一个个插槽所组成的槽链来实现的。Sentinel默认的各个插槽之间的顺序是固定的,因为有的插槽实现需要依赖其他插槽的数据统计。Sentinel也提供用户自定义方式实现插槽,但则只能放在默认Slot链的尾部。如果用户想自定义Slot链,可以实现**SlotChainBuilder**来自定义Slot的顺序编排。

  • Slot Chain:DefaultProcessSlotChain(first) -> NodeSelectorSlot -> ClusterBuilderSlot -> LogSlot -> StatisticSlot -> AuthoritySlot -> SystemSlot -> FlowSlot -> DegradeSlot(end)
    • NodeSelectorSlot:负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级。
    • ClusterBuilderSlot:用于存储资源的统计信息以及调用信息
    • LogSlot:用于记录日志信息
    • StatisticSlot:用于记录不同维度的runtime信息,Pass、Block、
    • AuthoritySlot:根据黑白名单来进行控制
    • SystemSlot:通过系统状态来控制总的入口流量
    • FlowSlot:用于根据预设的限流规则,以及前面的slot统计状态,来进行限流
    • DegradeSlot:通过统计信息以及预设的规则,来进熔断降级。

SlotChain.png

ProcessorSlot.png

  • SlotChain初始化**->执行链路:**
    • SlotChain初始化:CtSph的lookProcessChain,该方法会根据资源先从一个静态Map中获取SlotChain,若取不到才会进行初始化。这也表明同一个资源会全局共享一个SlotChain。

1.3、上下文-Context

This class holds metadata of current invocation。记录当前调用链的元数据,元数据包含:

  • entranceNode:当前调用链的入口节点
  • curEntry:调用链当前处理实体
  • origin:当前调用链的调用源,如服务消费者名称或者源IP

每次SphU.entry() 或 SphO.entry()的调用流程需要在一个Context中执行,如果当前执行时还没有 context,那么框架会使用默认的 context,默认的 context 是通过 MyContextUtil.myEnter() 创建。若用户想自定义Context,调用ContextUtil.enter来实现。

  • NodeSelectorSlot中的map,key为context的name而不是资源的name,原因是为了同一个资源多次调用,对应不同的Context,在各自执行完成后,再通过ClusterNode来进行合并。
  • 资源调用链路??】同一个context中对同一个resource进行多次entry()调用时,会形式一颗调用树,这个树是通过CtEntry之间的parent/child关系维护的。

## 1.4、凭证-Entry **Entry**是Sentinel用来标识是否进行限流降级的一个凭证,类似于一个token。每次执行`SphU.entry()` 或 `SphO.entry()`时都会返回一个Entry实体给调用者。告诉调用者如果正确返回了 `Entry`,那表示可以正常访问被sentinel保护的后方服务了,否则sentinel会抛出一个BlockException(如果是 `SphO.entry()`会返回false),这就表示调用者想要访问的服务被保护,即调用者本身被限流了。
  • Entry中包含了当前执行的一些基本信息:

    • createTime:创建Entry实体的时间,主要后面用于计算rt
    • curNode:当前执行节点
    • originNode:当前执行流程源节点,通常是调用方的应用名称
    • error:
    • resourceWrapper:当前Entry关联的资源
  • 当在一个上下文中多次调用了 SphU.entry()方法时,就会创建一个调用树,这个树的节点之间是通过parent和child关系维持的。需要注意的是:parent和child是在 CtSph类的一个私有内部类 CtEntry中定义的,CtEntryEntry的一个子类。

  • ** SphU.entry 方法的第二个参数 EntryType 说的是这次请求的流量类型,共有两种类型:IN 和 OUT 。**

    • IN:是指进入我们系统的入口流量,比如 http 请求或者是其他的 rpc 之类的请求。
    • OUT:是指我们系统调用其他第三方服务的出口流量。

1.5、节点-Node

Node.png

Node中保存了资源的实时统计数据,入passQps、blockQps、Rt等信息。Sentinel也是依据于这些数据才能实现限流降级等功能。Node的唯一统计实现类为StatisticNode。

  • EntranceNode是每个上下文的入口节点类,该节点是直接挂在root下的,是全局唯一的,每一个context都会对应一个entranceNode。
public final static DefaultNode ROOT = new EntranceNode(new StringResourceWrapper(ROOT_ID, EntryType.IN),
        new ClusterNode());
  • DefaultNode是记录当前调用的实时数据的,每个defaultNode都关联着一个资源和clusterNode,有着相同资源的defaultNode,他们关联着同一个clusterNode。

image.png

1.6、度量-Metric

Metric是sentinel中用来进行实时数据统计的度量接口,Node就是通过Metric来进行数据统计的。而Metric本身也并没有统计的能力,他也是通过Window来进行统计的。
Metric的实现类ArrayMetric,其通过LeapArray来实现对窗口的统计。

2、Sentinel调用链

Sentinel的一堆Slot构成了调用链路,从SphU.entry或者Sph0.entry开始,到lookProcessChain初始化slotchain,再调用ProcessorSlot的entry进入slot调用链。
每个Slot执行完逻辑后,都会调用fireEntry()方法,会触发下一个节点的entry()方法,下一个节点又会调用他的fireEntry,以此类推直到最后一个Slot,由此就形成了sentinel的责任链。
每次链调用一个资源,关联着一个Context,每个Context包含entranceNode、curEntry、originNode(名字)

image.png

  • 再提一下几个核心的角色:
    • Context
    • Entry
    • Node

image.png

2.1、Context创建与销毁

  • 创建:Context的创建由ContextUtil.trueEnter来实现。
protected static Context trueEnter(String name, String origin) {
   
    //从ThreadLocal中获取Context
    Context context = contextHolder.get();
    if (context == null) {
   
        //如果ThreadLocal中获取不到Context,则根据contextName从map中获取根节点,只要是相同的资源名,就能直接从map中获取到Node(入口节点)
        Map<String, DefaultNode> localCacheNameMap = contextNameNodeMap;
        DefaultNode node = localCacheNameMap.get(name);
        if (node == null) {
   
            //当然context还没有入口节点,则判断已存在的个数大小,或者重新创建
            if (localCacheNameMap.size() > Constants.MAX_CONTEXT_NAME_SIZE) {
   
                setNullContext();
                return NULL_CONTEXT
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只打杂的码农

你的鼓励是对我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值