4.1.2 滑动窗口
如果想知道某个接口的每秒请求成功总数(success QPS)、每秒请求失败总数(exception QPS),以及处理每个请求的平均耗时(avg RT),则只需要设置滑动窗口的大小为1秒即可。但如果想获取最近1分钟内的某1秒的QPS指标数据,就需要将滑动窗口的大小设置为1分钟,采样总数设置为60,采样周期设置为1秒,这时,该滑动窗口拥有60个Bucket,每个Bucket可以统计1秒的指标数据,若想要获取某1秒的Bucket,则只需要根据时间戳定位Bucket即可。
假设滑动窗口的大小为1分钟,采样总数为60,采样周期为1秒,给定一个时间戳如何定位到Bucket呢?
首先将当前时间戳去掉毫秒部分得到当前的秒数,然后将得到的秒数与数组长度做取余运算,即可得到当前时间窗口的Bucket在数组中的位置,如图4.2所示。
图4.2 定位Bucket在数组中的位置
定位当前时间戳对应的Bucket在滑动窗口的Bucket数组中的位置,其算法实现如下。
• windowLengthInMs:Bucket的时间窗口大小。
• timeMillis:当前时间戳。
• array:当前滑动窗口的Bucket数组。
想要获取连续的1分钟内的Bucket数据,就不能简单地从头开始遍历数组,正确做法是指定一个开始时间戳和结束时间戳,从开始时间戳开始计算Bucket存放在数组中的下标,根据下标获取Bucket,然后在每次循环时将开始时间戳加上1秒,直到开始时间戳等于结束时间戳。
由于滑动窗口会随着时间向前滑动,Bucket数组会被循环使用,当前时间戳与1分钟之前的时间戳和1分钟之后的时间戳都会被映射到数组中的同一个Bucket,因此必须能够判断指定的时间戳是否在取得的Bucket的时间窗口内,这就要求数组中的每个元素都要存储Bucket的时间窗口的开始时间戳和时间窗口大小。
例如,当前时间戳是1577017699235,Bucket的时间窗口大小是1秒,将时间戳的毫秒部分全部替换为0,就能得到Bucket的时间窗口的开始时间戳为1577017699000。
计算Bucket的时间窗口的开始时间戳的代码如下。
• windowLengthInMs:Bucket的时间窗口大小。
• timeMillis:当前时间戳。