共计 3294 个字符,预计需要花费 9 分钟才能阅读完成。
一,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 的整体工作流程
正文完