写点什么

Sentinel 的整体工作流程分析

  • 2023-06-10
    湖南
  • 本文字数:2511 字

    阅读完需:约 8 分钟

Sentinel 的整体工作流程如下:

  1. 调用 ContextUtil#enter 方法创建 Context 实例,创建的 Context 实例会被存储到 ThreadLocal 中,在调用链上可以随时获取该 Context 实例。

  2. 调用 SphU#entry 方法创建 CtEntry 实例,调用 ProcessorSlotChain#entry 方法。如果是首次访问资源,则需要为资源创建 ProcessorSlotChain。注册在 ProcessorSlotChain 上的每个 ProcessorSlot 都是一个流量切入点。

  3. 若在调用 SphU#entry 方法时抛出 BlockException,则说明当前请求被拒绝;若在调用业务方法时抛出异常,则会收集异常指标数据。

  4. 在调用 SphU#entry 方法后,需要确保调用一次 SphU#entry 方法返回的 Entry 实例的 exit 方法,并由 Entry 实例调用 ProcessorSlotChain 的 exit 方法。

  5. 在调用 ContextUtil#entry 方法后,需要确保调用一次 ContextUtil#exit 方法,将 Context 实例从 ThreadLocal 中移除。


如果不借助 Sentinel 提供的适配模块,则可以采用下面的方法使用 Sentinel,代码如下:

  1. 调用 ContextUtil#enter 方法。

  2. 调用 SphU#entry 方法,该方法会为资源创建 Entry 实例。

  3. 若抛出异常,且非 BlockException 异常,则调用 Tracer#trace 方法统计异常。

  4. 调用资源的 Entry#exit 方法。

  5. 调用 ContextUtil#exit 方法。

1、ContextUtil#enter 方法

ContextUtil#enter 方法负责在调用链入口创建 Context 实例,以及为调用链创建入口节点,即 EntranceNode 实例,源码如下:

  1. ContextUtil 使用 ThreadLocal 存储 Context,若当前调用链上已经存在 Context,则使用已经存在的 Context,否则创建 Context。

  2. 尝试从缓存中获取已经存在的入口节点。

  3. 若不存在入口节点,则创建入口节点,入口节点的名称与 Context 的名称相同。

  4. 将入口节点添加到调用树的 ROOT 节点的子节点中。


入口节点是一个调用链入口,只能被创建一个,并且作为调用树根节点(ROOT)的子节点。

2、SphU#entry 方法

Sentinel 的核心骨架是 ProcessorSlotChain,所以核心的流程是一次 SphU#entry 方法的调用及一次 Entry#exit 方法的调用。


SphU#entry 方法会调用 CtSph#entry 方法。CtSph 的作用如下:为资源创建 ResourceWrapper 对象并为资源构造一个全局唯一的 ProcessorSlotChain,为资源创建 CtEntry 并将 CtEntry 赋值给当前调用链上下文的 curEntry 字段,调用 ProcessorSlotChain#entry 方法完成一次 ProcessorSlot 单向链表的 entry 方法调用。


ProcessorSlotChain#entry 方法的调用过程如图 3.1 所示:

3、Tracer#trace 方法

当调用 SphU#entry 方法或执行资源方法抛出异常时,如果抛出的是非 BlockException 异常,则调用 Tracer#trace 方法统计异常指标。


Tracer#trace 方法最终会调用 Tracer#traceExceptionToNode 方法。


Tracer#traceExceptionToNode 方法的源码如下:

Sentinel 只为一个资源创建一个 ClusterNode,用于统计一个资源的全局指标数据,熔断降级与限流降级都使用了这个 ClusterNode。


ClusterNode 类的 trace 方法的实现代码如下:

4、Entry#exit 方法

在调用 SphU#entry 方法时,SphU#entry 方法会返回一个 CtEntry 实例,那么在调用资源方法后,无论是出现异常还是正常执行完成,都需要调用一次该 CtEntry 实例的 exit 方法。


下面是 CtEntry 实例的 exit 方法的实现,为了简短且易于理解,给出的是删减后的 exitForContext 方法的源码:

CtSph 在创建 CtEntry 实例时,将资源的 ProcessorSlotChain 赋值给了 CtEntry 实例,所以在调用 CtEntry 实例的 exit 方法时,CtEntry 实例能够拿到当前资源的 ProcessorSlotChain,并调用 ProcessorSlotChain 的 exit 方法完成一次单向链表的 exit 方法调用。其调用过程与 ProcessorSlotChain#entry 方法的调用过程一样。


在前面介绍 CtEntry 时提到过,CtEntry 用于维护父子 Entry,每调用一次 SphU#entry 方法都会创建一个 CtEntry 实例。如果在应用处理一次请求的路径上多次调用 SphU#entry 方法,那么这些 CtEntry 实例会构成一个双向链表。在每次创建 CtEntry 实例时,都会将 Context 实例的 curEntry 字段指向这个新的 CtEntry 实例,双向链表的作用就是在调用 CtEntry 实例的 exit 方法时,能够将 Context 实例的 curEntry 字段指向上一个 CtEntry 实例。

5、ContextUtil#exit 方法

ContextUtil#enter 方法在调用链入口创建 Context 实例,且创建的 Context 实例会被存储到 ContextUtil 类的一个类型为 ThreadLocal 的静态变量中,因此在退出方法之前必须调用一次 ContextUtil#exit 方法,从而将 Context 实例从 ThreadLocal 中移除。


ContextUtil#exit 方法的源码如下:

如果 Context 实例的 curEntry 字段值为空,则说明所有 SphU#entry 方法创建的 Entry 实例都执行了一次 exit 方法,此时就可以将 Context 实例从 ThreadLocal 中移除。


ContextUtil#enter 方法与 ContextUtil#exit 方法并不是必须调用的,当不需要为资源区分不同调用链入口的配置限流规则时可以被省略,但 Context 实例是调用链上方法执行所依赖的环境,因此,在默认的情况下,Sentinel 会自动创建一个调用链入口名称为 sentinel_default_context 的 Context 实例,同时会创建一个调用链入口名称为 sentinel_default_context 的入口节点。


省略调用 ContextUtil#enter 方法与 ContextUtil#exit 方法的 demo 如下:

在处理一次请求的过程中,Sentinel 会为调用链上的每个资源都创建一个 CtEntry 实例,每个 CtEntry 实例引用资源对应的 ProcessorSlotChain。CtEntry 维护双向链表的目的:在下一个资源方法执行结束时,能够将 Context 实例引用的 CtEntry 实例回退为引用上一个资源方法的 CtEntry 实例,以便随时通过 Context 实例获取当前资源的 ProcessorSlotChain。


最后,再总结一下 Sentinel 的整体工作流程:

  1. 调用 ContextUtil#enter 方法创建 Context 实例,创建的 Context 实例会被存储到 ThreadLocal 中,在调用链上可以随时获取该 Context 实例。

  2. 调用 SphU#entry 方法创建 CtEntry 实例,调用 ProcessorSlotChain#entry 方法。如果是首次访问资源,则需要为资源创建 ProcessorSlotChain。注册在 ProcessorSlotChain 上的每个 ProcessorSlot 都是一个流量切入点。

  3. 若在调用 SphU#entry 方法时抛出 BlockException,则说明当前请求被拒绝;若在调用业务方法时抛出异常,则会收集异常指标数据。

  4. 在调用 SphU#entry 方法后,需要确保调用一次 SphU#entry 方法返回的 Entry 实例的 exit 方法,并由 Entry 实例调用 ProcessorSlotChain 的 exit 方法。

  5. 在调用 ContextUtil#entry 方法后,需要确保调用一次 ContextUtil#exit 方法,将 Context 实例从 ThreadLocal 中移除。

用户头像

加VX:bjmsb02 凭截图即可获取 2020-06-14 加入

公众号:程序员高级码农

评论

发布
暂无评论
Sentinel的整体工作流程分析_互联网架构师小马_InfoQ写作社区