reference:
前记
这几天又陆续面了2个大厂,一面都顺利的过了,等待这我的是未知的狂风暴雨
Sentinel是如何做限流的
一般来说,经常会通过@SentinelResource来标记一个方法,可以将这个被标记的方法看成是一个sentinel资源。以@SentinelResource为入口,找到其切面,看看切面拦截后的所做的工作
进入sentinelResource切面后,会执行SphU.entry方法,在这个方法中会对被拦截方法做限流和熔断的逻辑处理,如果触发熔断和限流,会抛出BlockException,我们可以指定BlockHandler方法来处理这个异常。而对于业务上的异常,我们可以配置fallBack方法来处理被拦截方法调用产生的异常
在SphU.entry方法中,Sentinel实现限流,熔断功能的流程如下:
-
获取Sentinel上下文(Context)
Context包含了资源调用的节点和Entry信息
- Context:进入Sentinel逻辑时,首先获取当前线程的Context,当任务执行完毕后,被清除当前线程的Context。Context代表调用链路上下文,贯穿一次调用链路中的所有entry。Context维持这入口节点(entranceNode)本此调用链路的当前节点(curNode)调用来源(origin)等信息。Context名称即为调用链路入口名称
- Node:是对一个@SentinelResource标记的资源的统计包装,Context中记录本当前线程资源的入口节点,可以通过入口节点的childList 追溯资源的调用情况,每个节点都对应一个@sentinelResource标记的资源以及其统计数据,例如passQps blockQps rt等数据
- Entry:是Sentinel中用来表示是否通过限流的一个凭证,如果不通过会抛出BlockException。另外,他保存了本地执行entry方法的一些基本新,包括资源的Context Node 以及对应的责任链等信息、后续完成资源调用后,还需要获得这个entry去执行一些善后工作,包括退出entry对应的责任链,完成节点的一些统计信息更新,清楚当前线程的Context信息等
Context是线程持有的,利用ThreadLocal
-
获取资源对应的责任链
默认的责任链中处理节点包括 NodeSelectorSlot ClusterBuilderSlot StatisticSlot FlowSlot等,调用连(ProcessorSlotChain)和其中包含了所有Slot都实现了ProcessorSlot接口,采用责任链的模式执行各个节点的处理逻辑,并调用下一个节点。每个资源对应一条单独的责任链。先从缓存获取,没有则新建
-
生成资源调用凭证(Entry)
生成entry的是CtEntry。他的构造函数包含资源包装(ResourcewWrapper),资源对应的责任链以及当前线程的Context。CtEntry是一个双向链表,构建了sentinel资源的调用链路
-
执行责任链中各个节点
责任链和其中的Slot都实现了ProcessorSlot,责任链的entry方法会依次执行责任链各个Slot,所以下面就进入了责任链的各个Slot
-
NodeSelectorSlot 获取当前资源对应的Node,构建节点调用树
有三个作用:
- 在资源对应的调用链执行时,获取当前Context对应的NOde,这个Node代表这个资源的调用情况
- 将获取到的node设为当前node,添加到之前的node后面,形成树状调用路径
- 触发下一个Slot执行
NodeSelectorSlot获取资源对应的Node时,是用的Context的name,而不是SentinelResource的name。因为一个资源对应一个责任链。但是进入一个资源调用的Context却是不同的。比如如果用Dubbo Filter方式,生成的Context的name是Dubbo的接口限定名或者方法限定名,所有这样一种情况,不同的dubbo接口进来,都调用了同一个@SentinelResource标记的方法,那么折线方法对应的SentinelResource的在执行时对应的Context就是不同的
-
ClusterBuilderSlot–聚合相同资源的不同Context的node
ClusterNode的获取是以资源名为key,ClusterNode将会成为当前node的一个属性,主要为了聚合同一个资源不通Context情况下的多个node
-
StatisticSlot – 资源调用统计
主要负责资源调用统计信息的计算和更新
-
FlowSlot – 限流判断
上一步StatisticSlot对相关资源调用做的统计,在FlowSlot限流判断时会得到使用
- 首先获取资源对应的限流规则
- 根据规则检查是否被限流:主要是对qps计数进行先查
-
总结一下上述的步骤:NodeSelectorSlot用于获取资源对应的node,并构建node调用树,将SentinelSource的调用链路以Node Tree的形式组起来,ClusterBuilderSlot为当前node创建对应的CLusterNode,聚合相同资源对应的不同的Context的node,后续限流依据就是这个ClusterNode。ClusterNode继承自StatisticNode,记录着相应资源处理的一些统计数据,StatisticSlot用于更新资源调用的相关计数,FlowSlot更具Node的调用计数,判断是否限流
最后还有个收尾工作,Entry.exit()方法
最后再总结一下
- 三大组件Context、Entry、Node,是Sentinel的核心组件,各类信息及资源调用情况都由这三大类持有;
- 采用责任链模式完成Sentinel的信息统计、熔断、限流等操作;
- 责任链中NodeSelectSlot负责选择当前资源对应的Node,同时构建node调用树;
- 责任链中ClusterBuilderSlot负责构建当前Node对应的ClusterNode,用于聚合同一资源对应不同Context的Node;
- 责任链中的StatisticSlot用于统计当前资源的调用情况,更新Node与其对用的ClusterNode的各种统计数据;
- 责任链中的FlowSlot根据当前Node对应的ClusterNode(默认)的统计信息进行限流;
- 资源调用统计数据(例如PassQps)使用滑动时间窗口进行统计;
- 所有工作执行完毕后,执行退出流程,补充一些统计数据,清理Context。