LeapArray
字段
条件(谓词)更新锁,仅在不使用当前桶时使用。
内部核心数组 array,它的长度为 60,就是有 60 个窗口,每个窗口长度为 1 秒,一分钟走完一轮。
然后下一轮开启“覆盖”操作。
每个窗口是一个 WindowWrap 类实例。
添加数据的时候,先判断当前走到哪个窗口了(当前时间(s) % 60 即可),然后需要判断这个窗口是否是过期数据,如果是过期数据(窗口代表的时间距离当前已经超过 1 分钟),需要先重置这个窗口实例的数据。
统计数据同理,如统计过去一分钟的 QPS 数据,就是将每个窗口的值相加,当中需要判断窗口数据是否是过期数据,即判断窗口的 WindowWrap 实例是否是一分钟内的数据。
核心逻辑都封装在了 currentWindow(long timeMillis) 和 values(long timeMillis)方法中。
添加数据的时候,我们要先获取操作的目标窗口,也就是
分维度数据统计
currentWindow
Sentinel 在这里处理初始化和过期重置的情况
获取数据,使用的是
values
- 返回“有效”窗口中的数据
- isWindowDeprecated
案例
红色部分的Context 代表一个调用链的入口,Context 实例设置在 ThreadLocal,所以它是跟着线程走的,如果要切换线程,需要手动切换。
ContextUtil#enter 有俩参数:
- context name
调用链的入口,以区分不同调用链路,默认是 - origin
调用方标识,作用
黑白名单的授权控制
统计诸如从应用 application-a 发起的对当前应用 interfaceXxx() 接口的调用,目前这个数据会被统计,但是 dashboard 中并不展示
进入 BlockException 异常分支,代表该次请求被流量控制规则限制,一般会让代码走入到熔断降级逻辑。当然,BlockException 其实有好多个子类
亦可 catch 具体子类处理。
SphU#entry 方法的参数:
第一个参数
标识资源,通常就是我们的接口标识,对于数据统计、规则控制等,我们一般都是在这个粒度上进行的,根据这个字符串来唯一标识,它会被包装成 ResourceWrapper 实例。
第二个参数
标识资源的类型
- EntryType.IN
入口流量,比如我们的接口对外提供服务,那通常就是控制入口流量 - EntryType.OUT
- 默认就是出口流量,它的业务需要调用订单服务,像这种情况,压力其实都在订单服务,那就指定它为出口流量。
流量类型在 SystemSlot 类中用以实现自适应限流,根据系统健康状态来判断是否要限流,如果是 OUT 类型,由于压力在外部系统中,所以就不需要执行该规则。
若在一个方法中写,要注意内层的 Entry 先 exit,才能做外层的 exit,否则会抛出异常。源码角度来看,是在 Context 实例中,保存了当前的 Entry 实例。