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;
}
相关推荐
秋说1 小时前
【PTA数据结构 | C语言版】一元多项式求导
c语言·数据结构·算法
Maybyy2 小时前
力扣61.旋转链表
算法·leetcode·链表
卡卡卡卡罗特4 小时前
每日mysql
数据结构·算法
chao_7894 小时前
二分查找篇——搜索旋转排序数组【LeetCode】一次二分查找
数据结构·python·算法·leetcode·二分查找
lifallen5 小时前
Paimon 原子提交实现
java·大数据·数据结构·数据库·后端·算法
lixzest5 小时前
C++ Lambda 表达式详解
服务器·开发语言·c++·算法
EndingCoder5 小时前
搜索算法在前端的实践
前端·算法·性能优化·状态模式·搜索算法
丶小鱼丶5 小时前
链表算法之【合并两个有序链表】
java·算法·链表
不吃洋葱.5 小时前
前缀和|差分
数据结构·算法
jz_ddk8 小时前
[实战]调频(FM)和调幅(AM)信号生成(完整C语言实现)
c语言·算法·信号处理