一, 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步:
- 调用 ContextUtil#enter 办法。负责为以后调用链路创立 Context,创立好后存入ThreadLocal,以及为 Conetxt 创立 EntranceNode
- 调用 SphU#entry 办法。这里整体链路里的外围调用,CtSph 负责为资源创立 ResourceWrapper 对象并为资源结构一个全局惟一的 ProcessorSlotChain、为资源创立 CtEntry 并将 CtEntry 赋值给以后调用链路的 Context.curEntry、最初调用 ProcessorSlotChain#entry 办法实现一次单向链表的 entry 办法调用。
- 如果抛出异样,且异样类型非 BlockException 异样,则调用 Tracer#trace 办法记录异样,为以后资源的 DefaultNode 自增异样数
- 调用 Entry#exit 办法;
- 调用 ContextUtil#exit 办法。
参考文章:
06 Sentinel 中的责任链模式与 Sentinel 的整体工作流程