sentinel滑动窗口

ArrayMetric的类图如下所示,ArrayMetric是滑动窗口核心实现类,主要用于统计时间窗口的通过数、阻塞数、异常数,以及通过数、阻塞数、异常数的增加等,其包含了一个LeapArray<MetricBucket>类型的data成员变量;LeapArray可以看做一个时间窗口的数组,主要用于WindowWrap(时间窗口)的维护、当前时间对应的时间窗口的获取、当前时间窗口的开始时间的计算等;WindowWrap是时间窗口的具体实现类,内部维护了时间窗口的windowStart(开始时间)、窗口间隔(windowLengthInM)、指标桶(MetricBucket)等;MetricBucket相当于指标桶,主要通过LongAdder数组记录当前窗口的通过数、阻塞数、异常数,以及通过数、阻塞数、异常数的增加;

查看ArrayMetric.addPass方法,其首先调用LeapArray.currentWindowd方法,根据当前时间获取对应的WindowWrap(时间窗口),然后调用MetricBucket.addPass方法增加通过的请求数,MetricBucket中根据MetricEvent枚举的序数,维护着一个6个长度的LongAdder数组,用于记录当前窗口的通过、阻塞、异常、成功等的数量。

public void addPass(int count) {
    //获取当前的WindowWrap
    WindowWrap wrap = this.data.currentWindow();
    ((MetricBucket)wrap.value()).addPass(count);
}

LeapArray.currentWindow
public WindowWrap<T> currentWindow() {
    //根据当前时间获取WindowWrap
    return this.currentWindow(TimeUtil.currentTimeMillis());
}

public WindowWrap<T> currentWindow(long timeMillis) {
    if(timeMillis < 0L) {
        return null;
    } else {
        //根据传入的时间,计算所处窗口在数组中的角标
        int idx = this.calculateTimeIdx(timeMillis);
        //计算时间窗口开始的时间
        long windowStart = this.calculateWindowStart(timeMillis);
        while(true) {
            while(true) {
                //获取老的时间窗口
                WindowWrap old = (WindowWrap)this.array.get(idx);
                WindowWrap window;
                if(old == null) {
                    //如果老的窗口不存在,创建一个新窗口,并保存到数组中
                    window = new WindowWrap((long)this.windowLengthInMs, windowStart, this.newEmptyBucket(timeMillis));
                    if(this.array.compareAndSet(idx, (Object)null, window)) {
                        return window;
                    }
                    Thread.yield();
                } else {
                    if(windowStart == old.windowStart()) {
                        return old;
                    }
                    //如果老的窗口存在,并且老窗口的开始时间小于计算出的窗口开始时间,说明老窗口需要重置
                    if(windowStart > old.windowStart()) {
                        if(this.updateLock.tryLock()) {
                            try {
                                window = this.resetWindowTo(old, windowStart);
                            } finally {
                                this.updateLock.unlock();
                            }
                            return window;
                        }
                        Thread.yield();
                    } else if(windowStart < old.windowStart()) {
                        return new WindowWrap((long)this.windowLengthInMs, windowStart, this.newEmptyBucket(timeMillis));
                    }
                }
            }
        }
    }
}

LeapArray.calculateWindowStart
protected long calculateWindowStart(long timeMillis) {
    //计算窗口的开始时间
    return timeMillis - timeMillis % (long)this.windowLengthInMs;
}
MetricBucket.add
public MetricBucket add(MetricEvent event, long n) {
    this.counters[event.ordinal()].add(n);
    return this;
}

猜你喜欢

转载自blog.csdn.net/qq_33513289/article/details/111873387