-
NodeSelectorSlot:链中处理的第一个节点
责任链实例和 resource name 相关,和线程无关,所以当处理同一个resource 时,会进入同一 NodeSelectorSlot 实例。 所以该节点代码主要处理:不同的 context name,同一 resource name 的场景。
如下它们都处理同一 resource(“getUserInfo” resource),但它们入口 context 不一。
-
结合前面的那棵树,可得如下树
清楚 NodeSelectorSlot 实例和 resource 一一对应即可。
-
主要创建 ClusterNode
-
该类处理后
每个 resource 对应一个 ClusterNode 实例,若不存在,就创建一个新实例。
统计意义数据统计的。比如 getUserInfo 接口,由于从不同的 context name 开启调用链,它有多个 DefaultNode 实例,但只有一个 ClusterNode,通过该实例,即可知道该接口的 QPS。
此类还处理了 origin 不是默认值场景:
origin 代表调用方标识,如 application-a, application-b。
当设置了 origin,会生成一个 StatisticsNode 实例,挂在 ClusterNode。
改下案例代码
getUserInfo 接收到来自 application-a 和 application-b 两个应用的请求,那么树会变成下面这样:
它的作用是用来统计从 application-a 过来的访问 getUserInfo 这个接口的信息。目前该信息在 dashboard 不展示,毕竟没啥用。
LogSlot
直接 fire 出去了,即先处理责任链后面的节点,若它们抛 BlockException,才处理。
数据统计。
原理先 fire,等后面的节点处理完毕后,再进行统计数据。
-
为何这样设计? 因为后面节点是做控制,执行时可能正常通过,也可能抛 BlockException。
-
QPS 统计 使用滑动窗口
-
线程并发的统计 使用 LongAdder
接下来几个 Slot 需要通过 dashboard 进行开启,因为需要配置规则。
也可以硬编码规则到代码中。但是要调整数值就比较麻烦,每次都要改代码。
AuthoritySlot 作用权限控制,根据 origin 做黑白名单的控制:
在 dashboard 中,是这么配置的:
这里的调用方就是 origin。
SystemSlot 作用实现自适应限流。
-
规则校验都在 SystemRuleManager#checkSystem
我们先说说上面的代码中的 RT、线程数、入口 QPS 这三项系统保护规则。
-
dashboard 配置界面
-
StatisticSlot 类有下面一段
Sentinel 针对所有入口流量,使用了一个全局的 ENTRY_NODE 统计,系统保护规则是全局的,和具体某个资源没有关系。
由于系统的平均 RT、当前线程数、QPS 都可以从 ENTRY_NODE 中获得,所以限制代码非常简单,比较一下大小即可。超过阈值抛 SystemBlockException。
ENTRY_NODE 是 ClusterNode 类型,而 ClusterNode 对于 rt、qps 都是统计秒维度。
系统负载和 CPU 资源
Sentinel 通过调用 MBean 中的方法获取当前的系统负载和 CPU 使用率,Sentinel 起了一个后台线程,每秒查询一次。
-
dashboard 中对于 CPU 使用率的规则配置
Sentinel 本身定位就是个流控工具,所以 FlowSlot 非常重要。 这部分代码涉及到限流算法,稍复杂。
设 QPS 为 10,那么每 100ms 允许通过一个,通过计算当前时间是否已经过了上一个请求的通过时间 latestPassedTime 之后的 100 毫秒,来判断是否可以通过。假设才过了 50ms,那么需要当前线程再 sleep 50ms,然后才可以通过。如果同时有另一个请求呢?那需要 sleep 150ms。
DegradeSlot它有三个策略,我们首先说说根据 RT 降级:
若按照上面截图所示配置:对 getUserInfo 资源,正常情况下只需 50ms,若它的 RT 超过 100ms,则进入半降级状态,接下来的 5 次访问,如果都超过了 100ms,那么在接下来的 10 秒内,所有的请求都会被拒绝。
DegradeRule#passCheck
Sentinel 使用了 cut 作为开关,开启这个开关以后,会启动一个定时任务,过了 10秒 以后关闭这个开关。
达到阈值,开启断路器,之后由定时任务关闭。
客户端和 dashboard 交互-
sentinel-transport 三个子工程,common 是基础包和接口定义
若客户端要接入 dashboard,可以使用 netty-http 或 simple-http 中的一个。为何不直接使用 Netty,而要同时提供 http 选项? 因为你不一定使用 Java 来实现 dashboard,如果使用其他语言,使用 http 协议比较容易适配。
下面我们只介绍 http 的使用,首先,添加 simple-http 依赖:
<dependency> <groupId>com.alibaba.csp // 下面几行代码设置了 QPS 阈值是 100 FlowRule rule = new FlowRule("test"); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); rule.setCount(100); rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); List<FlowRule> list = new ArrayList<>(); list.add(rule); FlowRuleManager.loadRules(list); // 先通过一个请求,让 clusterNode 先建立起来 try (Entry entry = SphU.entry("test")) { } catch (BlockException e) { } // 起一个线程一直打印 qps 数据 new Thread(new Runnable() { @Override public void run() { while (true) { System.out.println(ClusterBuilderSlot.getClusterNode("test").passQps()); } } }).start(); while (true) { try (Entry entry = SphU.entry("test")) { Thread.sleep(5); } catch (BlockException e) { // ignore } catch (InterruptedException e) { // ignore } } }
然后观察下输出,QPS 数据在 50~100 这个区间一直变化,印证秒级 QPS 统计极度不准确。
参考
- https://www.javadoop.com/post/sentinel