一, Sentinel里的ProcessorSlot责任链

上一文里咱们介绍了Sentinel里的七种ProcessorSlot,它们分成两类,一类进行数据统计,一类实现降级性能。Sentinel整体工作流程是应用责任链模式将所有的ProcessorSlot依照肯定的程序组成一个单向链表辅助实现资源指标数据统计的 ProcessorSlot 必须在实现降级性能的 ProcessorSlot 的后面,起因很简略,降级性能须要根据资源的指标数据做判断,当然,如果某个 ProcessorSlot 不依赖指标数据实现降级性能,那这个 ProcessorSlot 的地位就没有束缚。

实现将 ProcessorSlot 串成一个单向链表的是 ProcessorSlotChain,这个 ProcessorSlotChain 是由 SlotChainBuilder 结构的,默认 SlotChainBuilder 结构的 ProcessorSlotChain 注册的 ProcessorSlot 以及程序如下代码所示。

public class DefaultSlotChainBuilder implements SlotChainBuilder {    @Override    public ProcessorSlotChain build() {        ProcessorSlotChain chain = new DefaultProcessorSlotChain();        chain.addLast(new NodeSelectorSlot());        chain.addLast(new ClusterBuilderSlot());        chain.addLast(new LogSlot());        chain.addLast(new StatisticSlot());        chain.addLast(new AuthoritySlot());        chain.addLast(new SystemSlot());        chain.addLast(new FlowSlot());        chain.addLast(new DegradeSlot());        return chain;    }}

如果是自定义的ProcessorSlot能够通过AbstractLinkedProcessorSlot进行构建

public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSlot<T> {    // 以后节点的下一个节点    private AbstractLinkedProcessorSlot<?> next = null;    public void setNext(AbstractLinkedProcessorSlot<?> next) {        this.next = next;    }      @Override    public void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args)        throws Throwable {        if (next != null) {            T t = (T) obj;             // 调用下一个 ProcessorSlot 的 entry 办法            next.entry(context,resourceWrapper,t,count,prioritized,args);        }    }    @Override    public void fireExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {        if (next != null) {            // 调用下一个 ProcessorSlot 的 exit 办法            next.exit(context, resourceWrapper, count, args);        }    }}

ProcessorSlot 接口的定义如下:

public interface ProcessorSlot<T> {    // 入口办法    void entry(Context context, ResourceWrapper resourceWrapper, T param, int count, boolean prioritized,Object... args) throws Throwable;    // 调用下一个 ProcessorSlot#entry 办法    void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized,Object... args) throws Throwable;    // 进口办法    void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args);    // 调用下一个 ProcessorSlot#exit 办法    void fireExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args);}

次要办法参数:

  • context:以后调用链路上下文。
  • resourceWrapper:资源 ID。
  • param:泛型参数,个别用于传递 DefaultNode。
  • count:Sentinel 将须要被爱护的资源包装起来,这与锁的实现是一样的,须要先获取锁能力继续执行。而 count 则与并发编程 AQS 中 tryAcquire 办法的参数作用一样,count 示意申请占用共享资源的数量,只有申请到足够的共享资源能力继续执行。例如,线程池有 200 个线程,以后办法执行须要申请 3 个线程能力执行,那么 count 就是 3。count 的值个别为 1,当限流规定配置的限流阈值类型为 threads 时,示意须要申请一个线程,当限流规定配置的限流阈值类型为 qps 时,示意须要申请 1 令牌(假如应用令牌桶算法)。
  • prioritized:示意是否对申请进行优先级排序,SphU#entry 传递过去的值是 false。
  • args:调用办法传递的参数,用于实现热点参数限流。

二,Sentinel整体工作流程

1,不借助 Sentinel 提供的适配器示例

ContextUtil.enter("上下文名称,例如:sentinel_spring_web_context");Entry entry = null;try {     entry = SphU.entry("资源名称,例如:/rpc/openfein/demo", EntryType.IN (或者 EntryType.OUT));     // 执行业务办法       return doBusiness();} catch (Exception e) {     if (!(e instanceof BlockException)) {          Tracer.trace(e);     }     throw e;} finally {     if (entry != null) {         entry.exit(1);     }     ContextUtil.exit();}

流程为5步:

  1. 调用 ContextUtil#enter 办法。负责为以后调用链路创立 Context,创立好后存入ThreadLocal,以及为 Conetxt 创立 EntranceNode
  2. 调用 SphU#entry 办法。这里整体链路里的外围调用,CtSph 负责为资源创立 ResourceWrapper 对象并为资源结构一个全局惟一的 ProcessorSlotChain、为资源创立 CtEntry 并将 CtEntry 赋值给以后调用链路的 Context.curEntry、最初调用 ProcessorSlotChain#entry 办法实现一次单向链表的 entry 办法调用。
  3. 如果抛出异样,且异样类型非 BlockException 异样,则调用 Tracer#trace 办法记录异样,为以后资源的 DefaultNode 自增异样数
  4. 调用 Entry#exit 办法;
  5. 调用 ContextUtil#exit 办法。

参考文章:
06 Sentinel 中的责任链模式与 Sentinel 的整体工作流程