QPS 滑动窗口限流

QPS 滑动窗口限流

AI 推理网关要做秒级 QPS 限流 :每个请求带毫秒时间戳(升序),滑动窗口大小为 windowMs,窗口内最多放行 allow 个请求,超出则拒绝。给定升序请求时间戳数组,返回可放行的请求数。

输入

  • timestamps[] int64:请求时间戳数组(升序,单位:毫秒)
  • windowMs int64:滑动窗口大小
  • allow int:窗口内最多允许放行的请求数

输出

可放行请求数。

示例

输入:

复制代码
timestamps = [100,150,200,500,600]
windowMs = 300
allow = 2

输出:

复制代码
4

示例解释

  • t=100:放行(窗口内 1 个)
  • t=150:放行(窗口内 2 个)
  • t=200:窗口内已有 2 个请求,拒绝
  • t=500:旧请求过期弹出,放行
  • t=600:放行

共放行 4 个请求。

QPS 限流和并发限流

假设服务器规定:

  • 300 毫秒内最多放行 2 个请求。
  • 每个请求的处理时间是 50 毫秒。

请求到达时间:

复制代码
t = 100:请求 A 到达
t = 150:请求 B 到达
t = 200:请求 C 到达

情况一:QPS 限流(本题)

复制代码
t = 100:A 放行
t = 150:A 处理完成,B 放行
t = 200:B 处理完成,C 拒绝

尽管 A、B 都已经处理完成,但在当前的 300 毫秒窗口内,已经放行了 2 个请求。

因此,C 仍然会被拒绝。

情况二:并发数限制

假设最多允许 2 个请求同时执行。

复制代码
t = 100:A 开始执行,并发数 = 1
t = 150:A 完成,B 开始执行,并发数 = 1
t = 200:B 完成,C 开始执行,并发数 = 1

由于请求处理完成会释放并发名额,因此三个请求都可以执行。

代码

cpp 复制代码
#include <deque>
#include <vector>
#include <iostream>
#include <cstdint>

using namespace std;

// qps 滑动窗口限流算法
// O(n) + O(min(n,allow)
int solve(vector<uint64_t> &timestamps, uint64_t windowMs, int allow) {
    int ans = 0;
    deque<uint64_t> q;
    for(uint64_t t : timestamps) {
        while(!q.empty() && t - q.front() >= windowMs) q.pop_front();
        if((int)q.size() < allow) {
            q.push_back(t);
            ++ ans;
        }
    }
    return ans;
}

int main()
{
    vector<uint64_t> timestamps{100, 150, 200, 500, 600};
    uint64_t windowMs = 200;
    int allow = 2;
    int ans = solve(timestamps, windowMs, allow);
    cout << ans << endl;
    
    return 0;
}