Sentinel

资源调用树

  • 调用链路树:Root为根结点的树,它的子节点是EntranceNode(Context),表示人为定义的调用上下文,EntranceNode的子节点是DefaultNode(Entry),表示资源调用,一个应用进程对应多个调用上下文,一个调用上下文对应多个资源
  • Root: 根结点,一个应用进程只有一个Root
  • Context: 调用上下文,一个应用可以创建多个,是人为定义的一组资源调用的集合,对应一个EntranceNode、上下文名称、来源。用于保存这一组资源调用的统计信息
  • DefaultNode:对应同一上下文的同一个资源,同一资源在同一上下文中调用多次,对应同一个DefaultNode。用于保存一个资源的调用信息,DefaultNode还可以有多个子DefaultNode,表示该资源调用过程中又调用了其它资源,
  • DefaultNode的统计信息不会求子DefaultNode的和,而是当前资源的统计信息,EntranceNode的统计信息是直接子节点的和
  • Entry: 表示某个资源的具体一次调用,同一上下文同一资源的每一次调用都对应一个Entry,这些调用只会对应一个DefaultNode
  • ProcessorChain:规则调用链,资源级的,同一资源对应同一个链,即使是在不同上下文中,但NodeSelectorSlot中又根据上下文名称区分了不同上下文的DefaultNode,所以DefaultNode是上下文+资源级的
  • NodeSelectorSlot:规则调用链的第一个槽位,用于创建DefaultNode,并将它添加到调用树的当前调用的资源Node的子节点
  • ClusterNode: 对应同一资源,不同上下文的资源也是对应同一个ClusterNode,默认情况下,即流控规则的来源配了default,并且时直接流控的话,使用ClusterNode来统计度量信息。
  • ClusterBuilderSlot:创建ClusterNode,并将它保存到DefaultNode
  • 流控规则的配置中,如果来源是default,流控规则是直接,则表示对当前资源进行流控;是关联,则表示对关联资源进行流控(获取关联资源的ClusterNode);是链路,表示对在指定上下文的当前资源进行流控
bash 复制代码
static Node selectReferenceNode(FlowRule rule, Context context, DefaultNode node) {
//流控规则是关联,就是关联资源;是链路,就是入口资源
    String refResource = rule.getRefResource();
    int strategy = rule.getStrategy();

    if (StringUtil.isEmpty(refResource)) {
        return null;
    }
    //流控规则是关联
    if (strategy == RuleConstant.STRATEGY_RELATE) {
        return ClusterBuilderSlot.getClusterNode(refResource);
    }
    //是链路
    if (strategy == RuleConstant.STRATEGY_CHAIN) {
        if (!refResource.equals(context.getName())) {
            return null;
        }
        return node;
    }
    // No node.
    return null;
}

滑动时间窗

  • 固定时间窗存在的问题:只统计当前请求所在的时间窗口的请求数,相邻的时间窗可能存在单位时间超出统计阈值
  • 滑动时间窗:为了解决上面的问题,统计当前请求最近一段时间的统计值,但又引发了新的问题:需要存储最近一段时间每个请求的时间戳,每次请求重新计算最近一段时间的请求数,存在存储和效率问题,而且对于密集的请求,存在重复计算的问题
  • 使用样本窗口的滑动时间窗:解决了滑动时间窗的问题,在滑动窗口内再细分多个样本窗口,新的请求数统计到当前样本窗口,已经过去的样本窗口不再重复计算,每次滑动n个样本窗口个单位的长度

统计数据的实现

bash 复制代码
public abstract class LeapArray<T> {
    //滑动窗口中样本的时间长度,windowLengthInMs=intervalInMs/sampleCount
    protected int windowLengthInMs;
    //滑动窗口中的样本数
    protected int sampleCount;
    //滑动窗口长度,毫秒
    protected int intervalInMs;
    //滑动窗口长度,秒
    private double intervalInSecond;
    //数组长度等于sampleCount,其中的元素是滑动窗口中每个样本的计量值
    protected final AtomicReferenceArray<WindowWrap<T>> array;
}
//WindowWrap用于保存计量数据的公共部分
public class WindowWrap<T> {
    //样本时间长度
    private final long windowLengthInMs;
    //样本开始时间戳
    private long windowStart;
    //具体的计量数据,就是MetricBucket
    private T value;
}
public class MetricBucket {
    //计量数据包含多个维度,维度类型在MetricEvent中,比如通过的请求数、异常数
    private final LongAdder[] counters;
}
bash 复制代码
//根据当前时间戳计算当前样本窗口的数组索引
private int calculateTimeIdx(/*@Valid*/ long timeMillis) {
    long timeId = timeMillis / windowLengthInMs;
    // Calculate current index so we can map the timestamp to the leap array.
    return (int)(timeId % array.length());
}
bash 复制代码
//根据当前时间戳计算计算当前样本窗口的起始时间戳
protected long calculateWindowStart(/*@Valid*/ long timeMillis) {
    return timeMillis - timeMillis % windowLengthInMs;
}

根据索引获取样本窗口,如果为空则初始化,否则根据当前样本窗口的起始时间戳和已存在的样本窗口进行比较,如果相等,则说明为同一样本窗口,否则是已经过期的窗口,重置它的起始时间和计量值

获取统计数据的实现

需要过滤掉样本窗口数组中已过期的窗口,用当前时间戳-样本窗口起始时间,如果大于滑动窗口长度,则为过期的窗口

bash 复制代码
public boolean isWindowDeprecated(long time, WindowWrap<T> windowWrap) {
    return time - windowWrap.windowStart() > intervalInMs;
}
相关推荐
算法歌者9 分钟前
[算法]入门1.矩阵转置
算法
林开落L24 分钟前
前缀和算法习题篇(上)
c++·算法·leetcode
远望清一色24 分钟前
基于MATLAB边缘检测博文
开发语言·算法·matlab
tyler_download26 分钟前
手撸 chatgpt 大模型:简述 LLM 的架构,算法和训练流程
算法·chatgpt
SoraLuna1 小时前
「Mac玩转仓颉内测版7」入门篇7 - Cangjie控制结构(下)
算法·macos·动态规划·cangjie
我狠狠地刷刷刷刷刷1 小时前
中文分词模拟器
开发语言·python·算法
鸽鸽程序猿1 小时前
【算法】【优选算法】前缀和(上)
java·算法·前缀和
九圣残炎1 小时前
【从零开始的LeetCode-算法】2559. 统计范围内的元音字符串数
java·算法·leetcode
YSRM1 小时前
Experimental Analysis of Dedicated GPU in Virtual Framework using vGPU 论文分析
算法·gpu算力·vgpu·pci直通
韭菜盖饭2 小时前
LeetCode每日一题3261---统计满足 K 约束的子字符串数量 II
数据结构·算法·leetcode