slidingWindow.jpeg
核心原理
滑动时间窗口的核心原理是: 我们先确认一个窗口,这个创建就是一个单位时间,比如10s, 统计10s内某个Redis的Key访问次数,这个10s就是一个单位时间窗口,如果仅仅以10s一个单位来做统计,这个就太粗糙了,而且结果不准确。
通常的做法是,将这个10s的窗口,进行一个切分,比如切分10个小块,每个小块代表 1 秒,这个切分的步骤,它的思想是来源于 桶排序中,桶的划分思想, 桶排序这个思想可以应用于很多方面,利用桶排序思想,其实我们具体利用的不是他的排序功能,而是这个 桶 的功能。
比如 Java中的高性能计数器 LongAddr
,底层的逻辑核心思想也是 桶 的思想
核心逻辑
既然利用滑动时间窗口做统计, 这里面的最核心的一个步骤,我觉得并不是 如何 做统计,而是 确认当前时间在窗口中的哪个小方块中,具体统计的计算,只是很自然的一步。
这里我们把小方块称为 桶, 对于当前时间,如何确定它应该放在哪个桶里面呢?
其实很简单:
-
(当前时间 - 窗口起始时间) / 1
, 这里的 1 表示一个桶的规格,实际也可以是3,4,5等
直接看代码
timeMillisPerSlice: 每个桶的大小
timeSliceSize:窗口内共有多少桶
/**
* 计算当前所在的时间片的位置
*/
private int currentIndex() {
long now = System.currentTimeMillis();
// 如果当前的key已经超出一整个时间片了,那么就直接初始化就行了,不用去计算了
if (now - lastAddTimestamp > timeMillisPerSlice * windowSize) {
reset();
}
return (int) (((now - beginTimestamp) / timeMillisPerSlice) % timeSliceSize);
}