本篇内容主要主要从理论及源码角度介绍sentinel降级和限流的核心原理。若是有对sentinel功能不了解的能够先阅读下《sentinel--初级使用篇》。 node
Sentinel 的核心骨架,将不一样的 Slot 按照顺序串在一块儿(责任链模式),从而将不一样的功能(限流、降级、系统保护)组合在一块儿。slot chain 其实能够分为两部分:统计数据构建部分(statistic)和判断部分(rule checking)。核心结构以下图: 缓存
Entry entry = null;
try {
entry = SphU.entry(KEY);
throw new RuntimeException("oops");
}catch (Throwable t) {
bizException.incrementAndGet();
// It\'s required to record exception here manually.
Tracer.traceEntry(t, entry);
} finally {
total.addAndGet(1);
if (entry != null) {
entry.exit();
}
}
先贴一段sentinel的基本使用用法,而后一路往下跟到下图:架构
①段代码会生成下面这样一颗树
这里的源码很是简单,若是咱们历来不显式调用 ContextUtil#enter 方法的话,那 root 就只有一个 default 子节点。context 很好理解,它表明线程执行的上下文,在各类开源框架中都有相似的语义,在 Sentinel 中,咱们能够看到,对于一个新的 context name,Sentinel 会往树中添加一个 EntranceNode 实例。它的做用是为了区分调用链路,标识调用入口。 app
②处代码很是关键(lookProcessChain(resourceWrapper) 这个方法),内部实现以下 框架
经过SPI机制将META-INFO/servcie下配置好的默认责任链构造这加载出来,而后调用其builder()方法进行构建调用链 oop
责任链一样是由spi机制加载出来的,上面的加载只会在第一次使用的时候加载,而后缓存到内从后,之后直接取便可。其中责任链的构架过程相似有现行链表的构建过程,具体以下图,这里就不在过多赘述。ui
咱们前面说了,责任链实例和 resource name 相关,和线程无关,因此当处理同一个 resource 的时候,会进入到同一个 NodeSelectorSlot 实例中。该节点主要处理的是:不一样的 context name,同一个 resource name 的状况。以下面的两段代码: 线程
接下来,咱们来到了 ClusterBuilderSlot 这一环,这一环的主要做用是构建 ClusterNode。这里不贴源码,根据上面的树,而后在通过该类的处理之后,咱们能够得出下面这棵树:code
从上图能够看到,对于每个resource,这里会对应一个 ClusterNode 实例,若是不存在,就建立一个实例。这个 ClusterNode 很是有用,由于咱们就是使用它来作数据统计的。好比 getUserInfo 这个接口,因为从不一样的 context name 中开启调用链,它有多个 DefaultNode 实例,可是只有一个 ClusterNode,经过这个实例,咱们能够知道这个接口如今的 QPS 是多少。另外,这个类还处理了 origin 不是默认值的状况: blog
if (!"".equals(context.getOrigin())) {
Node originNode = node.getClusterNode().getOrCreateOriginNode(context.getOrigin());
context.getCurEntry().setOriginNode(originNode);
}
咱们能够看到,当设置了 origin 的时候,会额外生成一个 StatisticsNode 实例,挂在 ClusterNode 上。咱们把前面的代码改改,看红色部分:
咱们的 getUserInfo 接收到了来自 application-a 和 application-b 两个应用的请求,那么树会变成下面这样:
它的做用是用来统计从 application-a 过来的访问 getUserInfo 这个接口的信息。目前这个信息在 dashboard 中是不展现的,毕竟也没什么用。到此为止咱们的核心骨架就建立完成了。