learn-tech/专栏/深入理解Sentinel(完)/06Sentinel中的责任链模式与Sentinel的整体工作流程.md
2024-10-16 09:22:22 +08:00

18 KiB
Raw Blame History

                        因收到Google相关通知网站将会择期关闭。相关通知内容
                        
                        
                        06 Sentinel 中的责任链模式与 Sentinel 的整体工作流程
                        上一篇我们简单了解了 ProcessorSlot并且将 Sentinel 提供的所有 ProcessorSlot 分成两类,一类是辅助完成资源指标数据统计的 ProcessorSlot一类是实现降级功能的 ProcessorSlot。

Sentinel 的整体工具流程就是使用责任链模式将所有的 ProcessorSlot 按照一定的顺序串成一个单向链表。辅助完成资源指标数据统计的 ProcessorSlot 必须在实现降级功能的 ProcessorSlot 的前面,原因很简单,降级功能需要依据资源的指标数据做判断,当然,如果某个 ProcessorSlot 不依赖指标数据实现降级功能,那这个 ProcessorSlot 的位置就没有约束。

除了按分类排序外,同一个分类下的每个 ProcessorSlot 可能也需要有严格的排序。比如辅助完成资源指标数据统计的 ProcessorSlot 的排序顺序为:

NodeSelectorSlot->ClusterBuilderSlot->StatisticSlot

如果顺序乱了就会抛出异常,而实现降级功能的 ProcessorSlot 就没有严格的顺序要求AuthoritySlot、SystemSlot、FlowSlot、DegradeSlot 这几个的顺序可以按需调整。

实现将 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 或者添加自定义的 ProcessorSlot下一篇再作介绍。

ProcessorSlot 接口的定义如下:

public interface ProcessorSlot { // 入口方法 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); }

例如实现熔断降级功能的 DegradeSlot其在 entry 方法中检查资源当前统计的指标数据是否达到配置的熔断降级规则的阈值,如果是则触发熔断,抛出一个 DegradeException必须是 BlockException 的子类),而 exit 方法什么也不做。

方法参数解析:

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

ProcessorSlotChain

之所以能够将所有的 ProcessorSlot 构造成一个 ProcessorSlotChain还是依赖这些 ProcessorSlot 继承了 AbstractLinkedProcessorSlot 类。每个 AbstractLinkedProcessorSlot 类都有一个指向下一个 AbstractLinkedProcessorSlot 的字段,正是这个字段将 ProcessorSlot 串成一条单向链表。AbstractLinkedProcessorSlot 部分源码如下。

public abstract class AbstractLinkedProcessorSlot implements ProcessorSlot { // 当前节点的下一个节点 private AbstractLinkedProcessorSlot next = null;

public void setNext(AbstractLinkedProcessorSlot<?> next) {
    this.next = next;
}

}

实现责任链调用是由前一个 AbstractLinkedProcessorSlot 调用 fireEntry 方法或者 fireExit 方法,在 fireEntry 与 fireExit 方法中调用下一个 AbstractLinkedProcessorSlotnext的 entry 方法或 exit 方法。AbstractLinkedProcessorSlot 的 fireEntry 与 fireExit 方法的实现源码如下:

public abstract class AbstractLinkedProcessorSlot implements ProcessorSlot { // 当前节点的下一个节点 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);
    }
}

}

ProcessorSlotChain 也继承 AbstractLinkedProcessorSlot只不过加了两个方法提供将一个 ProcessorSlot 添加到链表的头节点的 addFirst 方法,以及提供将一个 ProcessorSlot 添加到链表末尾的 addLast 方法。

ProcessorSlotChain 的默认实现类是 DefaultProcessorSlotChainDefaultProcessorSlotChain 有一个指向链表头节点的 first 字段和一个指向链表尾节点的 end 字段,头节点字段是一个空实现的 AbstractLinkedProcessorSlot。DefaultProcessorSlotChain 源码如下。

public class DefaultProcessorSlotChain extends ProcessorSlotChain { // first指向链表头节点 AbstractLinkedProcessorSlot first = new AbstractLinkedProcessorSlot