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;private final ReentrantLock updateLock = new ReentrantLock();public LeapArray(int sampleCount, int intervalInMs) {AssertUtil.isTrue(sampleCount > 0, "bucket count is invalid: " + sampleCount);AssertUtil.isTrue(intervalInMs > 0, "total time interval of the sliding window should be positive");AssertUtil.isTrue(intervalInMs % sampleCount == 0, "time span needs to be evenly divided");// 1000 / 2  60*1000/60 = 1000this.windowLengthInMs = intervalInMs / sampleCount;// 1000  60*1000 60秒this.intervalInMs = intervalInMs;// 1 60this.intervalInSecond = intervalInMs / 1000.0;// 2 60this.sampleCount = sampleCount;// 2this.array = new AtomicReferenceArray<>(sampleCount);}
}

2.3.1 更新当前时间点某个统计量

调用ArrayMetricaddXXX()方法,这里以addPass()为例。

  • 首先根据当前时间获取所属时间窗,即调用LeapArraycurrentWindow()方法。在此方法里面就完成了时间窗的更新,时间窗数组的轮转,具体见currentWindow()方法。
  • 然后调用时间窗的里面的metricBucket更新pass
public void addPass(int count) {// 获取当前时间所属的时间窗WindowWrap<MetricBucket> wrap = data.currentWindow();// wrap.value().addPass(count);
}

LeapArraycurrentWindow()方法,此方法很重要会更新数组各个位置的时间窗为最新的时间窗,更新即重置时间窗的起始时间以及将里面的统计量进行归零。


public WindowWrap<T> currentWindow() {return currentWindow(TimeUtil.currentTimeMillis());
}public WindowWrap<T> currentWindow(long timeMillis) {if (timeMillis < 0) {return null;}// 计算当前时间对应的时间窗在数组中的位置:////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());// }int idx = calculateTimeIdx(timeMillis);// Calculate current bucket start time.// 计算时间窗的起始时间// protected long calculateWindowStart(/*@Valid*/ long timeMillis) {//    return timeMillis - timeMillis % windowLengthInMs;//  }long windowStart = calculateWindowStart(timeMillis);while (true) {// 从时间窗数组里面获取时间窗WindowWrap<T> old = array.get(idx);if (old == null) {// 如果为空则创建一个新的时间窗WindowWrap<T> window = new WindowWrap<T>(windowLengthInMs, windowStart, newEmptyBucket(timeMillis));// 使用cas方法if (array.compareAndSet(idx, null, window)) {// Successfully updated, return the created bucket.return window;} else {// Contention failed, the thread will yield its time slice to wait for bucket available.Thread.yield();}// 如果时间窗的起始时间与当前时间所属时间窗的起始时间相等,那么就直接返回此时间窗} else if (windowStart == old.windowStart()) {return old;// 当前时间所属时间窗的起始时间大于获取到的时间窗的起始时间// 则更新获取到的时间起始时间,以及重置时间窗里面的统计量的值} else if (windowStart > old.windowStart()) {// 加锁if (updateLock.tryLock()) {try {// Successfully get the update lock, now we reset the bucket.return resetWindowTo(old, windowStart);} finally {updateLock.unlock();}} else {// Contention failed, the thread will yield its time slice to wait for bucket available.Thread.yield();}} else if (windowStart < old.windowStart()) {// Should not go through here, as the provided time is already behind.return new WindowWrap<T>(windowLengthInMs, windowStart, newEmptyBucket(timeMillis));}}
}

2.3.2 获取某个统计值

调用ArrayMetric的xxx()方法

    public long pass() {// 获取当前的时间窗口,实际上是更新时间窗data.currentWindow();long pass = 0;// 获取需要进行统计的时间窗里面的MericBucket,这里返回的是List<MetricBucket>// 实际上也可以看成返回的是List<WindowWrap>List<MetricBucket> list = data.values();for (MetricBucket window : list) {// 遍历计量桶,进行累加,计算通过的值pass += window.pass();}return pass;}

LeapArrayvalues()方法

public List<T> values() {return values(TimeUtil.currentTimeMillis());
}public List<T> values(long timeMillis) {if (timeMillis < 0) {return new ArrayList<T>();}int size = array.length();// 初始化List<T> result = new ArrayList<T>(size);// 遍历时间窗数组,获取每一个元素for (int i = 0; i < size; i++) {WindowWrap<T> windowWrap = array.get(i);// 对应的时间窗为空,或者不属于当前统计的区间if (windowWrap == null || isWindowDeprecated(timeMillis, windowWrap)) {continue;}// 在这里真正的加入值result.add(windowWrap.value());}return result;
}关键点:
public boolean isWindowDeprecated(long time, WindowWrap<T> windowWrap) {// 当前时间值减去当前时间窗口的开始值 是否大于统计区间的值return time - windowWrap.windowStart() > intervalInMs;
}

我理解的Sentinel:时间窗统计相关推荐

  1. 如何理解FFT中时间窗与RBW的关系

    作为一种常用的频谱分析工具,快速傅里叶变换(FFT) 实现了时域到频域的转换,是数字信号分析中最常用的基本功能之一.FFT 频谱分析是否与传统的扫频式频谱仪类似,也具有分辨率带宽(RBW) 的概念?如 ...

  2. 【小工具】滑动时间窗统计单位时间内访问频率

    起因 想要完成一个个人轻量级微服务框架,负载均衡和接口安全都需要一个这样的工具来统计访问频率,那么就选择了一种比较传统的方式来实现,其他博客中有提供一些方式,但设计较为简单,不能满足我的需求,所以再起 ...

  3. rbw数字信号处理_如何理解FFT中时间窗与RBW的关系

    傅里叶变换(FFT)实现了时域到频域的转换,是信号分析中最常用的基本功能之一.本文将描述FFT应用中为什么要采用时间窗,以及RBW与时间窗的关系. FFT变换是在一定假设下完成的,即认为被处理的信号是 ...

  4. hanning窗?hamming窗?如何理解语音信号处理中时间窗的作用

    参考:如何理解FFT中时间窗与RBW的关系 - 知乎 - 如何理解FFT中时间窗与RBW的关系 hanmming窗和hamming窗的作用_西檬饭-CSDN博客_hamming - hanning窗和 ...

  5. 风控特征—时间滑窗统计特征体系

    " 本文介绍了风控业务中构建时间滑窗特征的一些实践经验,是一篇既能让读者快速上手特征工程又能加深其业务理解的深度好文." 作者:求是汪在路上 来源:知乎专栏 风控模型算法. 编辑: ...

  6. 风控特征:时间滑窗统计特征体系

    风控业务背景 俗话说, 路遥知马力,日久见人心.在风控中也是如此,我们常从时间维度提取借款人在不同时间点的特征,以此来判断借款人的风险.在实践中,这类特征通常会占到80%以上.由于是通过时间切片和聚合 ...

  7. Sentinel滑动时间窗限流算法

    Sentinel系列文章 Sentinel熔断限流器工作原理 Sentinel云原生K8S部署实战 Sentinel核心源码解析 时间窗限流算法 如图 10-20这个时间窗内请求数量是60小于阈值10 ...

  8. Sentinel滑动时间窗限流算法原理及源码解析(中)

    文章目录 MetricBucket MetricEvent数据统计的维度 WindowWrap样本窗口实例 范型T为MetricBucket windowLengthInMs 样本窗口长度 windo ...

  9. Sentinel滑动时间窗限流算法原理及源码解析(上)

    文章目录 时间窗限流算法 滑动时间窗口 滑动时间窗口算法改进 滑动时间窗口源码解析 时间窗限流算法 10t到16t 10个请求 16t-20t 50个请求 20t-26t 60个请求 26t到30t ...

  10. sentinel 时间窗口的实现

    本文的github地址点击这里 获取时间窗口的主要流程 在 Sentinel 中,主要是通过 LeapArray 类来实现滑动时间窗口的实现和选择.在 sentinel 的这个获取时间窗口并为时间窗口 ...

最新文章

  1. Vue引入百度地图,如何去掉左下角的版权logo百度等信息?
  2. [恢]hdu 2521
  3. 创建azure服务器
  4. 大数据 清华 覃征_清华大学人工智能研究院大数据智能研究中心揭牌,喊你来参与...
  5. opencv怎么2个摄像头_最后2个月,怎么做能够快速提分?
  6. linux 取出字符中数字,使用awk提取字符串中的数字或字母
  7. POSIX定时器Timer
  8. Windows 2003中如何启动IIS6的GZIP压缩网页传输(补充)
  9. 每周一磁 · 磁性材料的居里温度与工作温度
  10. 解决VS停止调试时浏览器自动关闭关闭浏览器时自动停止调试
  11. spring security +oauth2(授权服务和资源服务分离) 解决getPrincipal只返回用户名的问题
  12. MAC 录屏工具,录制视频制作GIF—— LICEcap
  13. 用java计算一元二次方程
  14. 千里之遥看樱花,“东湖·樱园”元宇宙
  15. Java 对象 、String 、JSON 互转
  16. EEPROM, NAND FLASH, NOR FLASH
  17. greasemonkey 使用心得
  18. 英文连写字体怎么练_衡水英文字体视频教程
  19. 经度从0-360更改为-180到180
  20. 联想rd640服务器装系统,RD640操作系统安装手册.pdf

热门文章

  1. 大学抢课python脚本_用彪悍的Python写了一个自动选课的脚本 | 学步园
  2. 给英文文章加音标,建生词表
  3. 海康威视 私有网盘 windows 客户端下载地址
  4. 台式计算机开关电源原理图,计算机开关电源基本结构及原理介绍
  5. 国产操作系统Deepin安装
  6. CUMT矿大----电路与数字系统实验一 一位全减器
  7. 实时任务多核分区调度算法—近似率 asymptotic approximation ratio的概念和作用
  8. 罗马数字包含以下七种字符: `I, V, X, L,C,D M`
  9. python银行系统-python实现简单银行管理系统
  10. 怎么用imp命令把dmp文件从本地导入到远处的数据库服务器,Oracle 数据库导入导出dmp文件...