QPS
2025年01月06日
一、认识
QPS(Queries Per Second)
表示系统每秒处理的请求数,是衡量系统性能的重要指标。使用 Redis
作为数据存储和统计工具,可以高效实现精准的 QPS
统计,尤其在高并发场景中表现出色。实现方案如下: 基于滑动窗口的 QPS
统计: 使用 Redis
的有序集合(ZSET
),将每个请求的时间戳记录为分数。动态统计过去 N
秒内的请求数,精准反映实时流量。
滑动窗口 通过更精细化的时间统计解决固定窗口的临界问题。它利用 Redis
有序集合(ZSET
)存储请求的时间戳,并动态调整统计范围,使得时间窗口可以 滑动。具体步骤为: 为每个用户或操作通过 ZADD
创建一个有序集合键,值为请求的时间戳。当用户发起请求时, 添加当前时间戳到有序集合,通过 ZREMRANGEBYSCORE
删除集合中超出时间窗口范围的旧时间戳, 通过 ZCARD
获取集合中当前时间窗口内的元素数量, 如果数量超过限制,拒绝请求, 并设置键的过期时间, 避免无用数据长期占用存储。滑动窗口 可以实现精细化统计,能够更精确地限制请求频率,避免流量突增,解决了固定窗口的临界问题,限流更加平滑,时间粒度更加精细。并具有高灵活性,可适用于更高要求的限流场景,例如对实时性要求较高的 API
。而且可以动态调整,可以灵活调整时间窗口和请求限制。
二、语法
const redis = require('redis');
const redisClient = redis.createClient();
redisClient.connect();
// 滑动窗口 QPS 统计
async function recordQPSSlidingWindow(windowInSeconds = 1) {
const currentTime = Date.now(); // 当前毫秒时间戳
const windowStart = currentTime - windowInSeconds * 1000; // 窗口开始时间
const key = `qps:zset`;
// 添加当前请求时间到有序集合
await redisClient.zAdd(key, { score: currentTime, value: currentTime.toString() });
// 删除窗口外的请求
await redisClient.zRemRangeByScore(key, 0, windowStart);
// 获取窗口内的请求数
const count = await redisClient.zCard(key);
// 设置过期时间,避免无用数据
await redisClient.expire(key, windowInSeconds + 1);
return count;
}
// 示例:记录请求并输出 QPS
(async () => {
const qps = await recordQPSSlidingWindow(1);
console.log(`QPS in the last 1 second: ${qps}`);
})();