1 时间窗口基础
参数:
- intervalLength: 区间长度,即统计的时间长度,决定了计算数据时统计的窗口个数
- windowLength:时间窗宽度
- count:时间窗内统计量
- startTime: 每个时间窗的起始时间
如下图所示,每个时间点都会归属于一个时间窗口,即会将时间轴按照时间窗宽度windowLength
进行划分。每个时间窗都有一个起始时间startTime
。
获取某个时间的统计量
- 获取当前时间currTime
- 根据currTime - (已用时间窗).startTime < intervalLength,找到参与统计时间窗
- 对参与时间窗的统计量count进行求和即可得到当前时间的统计量
更新某个时间的统计量
- 获取当前时间currTime
- 找到当前时间所属的时间窗,更新时间窗里面的count
上面的图示是在整个时间轴上进行划分的,有无穷多个时间窗。但是在具体实现上是不可能表示出无穷个时间窗的,所以实现时会使用一个固定大小的时间窗数组。采用复用/循环存储时间窗的方式。依据:在某个时间点只需要统计某几个时间窗的数据即可,而不需要知道所有时间窗的数据,所以只保存需要的几个时间窗
此时多了一个参数sampleCount
,数组的大小就是sampleCount
。
关系:sampleCount
=intervalLength / windowLength
更新某个时间点处的统计量:
- 获取当前时间currTime
- 计算当前时间点所属时间窗在数组中位置index = (currTime / windowLength) % sampleCount
- 获取时间窗window = array[index]
- 判断时间窗是否已过期:currTime - 时间窗.startTime > intervalLength;已过期则重置时间窗口,即将里面的统计量count归零,然后累加count;未过期直接累加count。
获取某个时间点的统计量
- 获取当前时间currTime
- 遍历时间窗数组,判断时间窗是否该统计:currTime - 时间窗.startTime < intervalLength
2 sentinel中时间窗的实现
主要的几个类:
LeapArray
时间窗的底层实现,里面有一个时间窗的数组,数组里面的元素为WindowWrap
,即时间窗WindowWrap<T>
时间窗,T表示要统计的数据,为MetricBucket
MetricBucket
统计量,里面包含了多个具体统计的变量,变量的"类型"由MetrciEvent
决定MetricEvent
统计量类型,和MetricBucktet里面保存的统计变量一一对应ArrayMetric
对外使用的类,隐藏了时间窗的具体实现,其有一个成员变量LeapArray
几个类之间的关系:
2.1 统计的量
需要统计的量在MetricEvent这个枚举变量表示
public enum MetricEvent {
PASS,
BLOCK,
EXCEPTION,
SUCCESS,
RT,
OCCUPIED_PASS
}
2.2 对外提供使用的类
典型用法:
// 创建实例,两个值:2-sampleCount 1000-统计的区间大小
arrayMetric = new ArrayMtric(2, 1000);
// 增加某个统计量的值
arrayMetric.addXXX(n);
// 获取某个统计量的值
arrayMetric.XXX()
当要使用时间窗进行统计时,对外提供的就是ArrayMetric
。它隐藏了具体的时间窗的实现。
它有一个成员变量:data=LeapArray<MetrciBucket>
即底层的时间窗实现类。
在某个时间点需要增加某个统计量的值,就调用addXXX
类型的API
在某个时间点需要获取某个统计量的值,就调用xxx()
类型的API
2.3 底层实现
主要分析两个操作:
- 更新值
- 获取值
首先是时间窗轮转数组LeapArray
,它是整个时间窗组件的主类。
public abstract class LeapArray<T> {
// 时间窗的大小
protected int windowLengthInMs;
// 采样数,即将统计区间划分成几等份
protected int sampleCount;
// 统计区间
protected int intervalInMs;
private double intervalInSecond;
protected final AtomicReferenceArray<WindowWrap<T>> array;
priva