滑动窗口实现访问频率限制
- 使用redis的有序集合实现滑动窗口,从而实现对访问频率的限制
-
- 思路一
- 思路二
使用redis的有序集合实现滑动窗口,从而实现对访问频率的限制
主要思路有两个
思路一
- 以时间戳为有序集合的成员
- 每次请求,先使用
命令移除窗口外的成员ZREMRANGEBYLEX
- 使用
命令获取有序集合的成员和相应权重ZRANGE
- 使用
命令对相应的成员的权重加一ZINCRBY
- 使用
命令重新设置有序集合有效期EXPIRE
- 对获取到的有序集合的成员的权重求和,并判断是否超过阈值
PHP实现
$maximum = 10; // 最大请求数量
$slidingWindow = 10; // 滑动窗口大小(s)
$now = time();
$redisKeyMod = 'pre:sliding_window:sorted_sets:%s';
$redisKey = sprintf($redisKeyMod, 'test.com');// 全站窗口
//$redisKey = sprintf($redisKeyMod, '/api/test/info');// 某个接口窗口
//$redisKey = sprintf($redisKeyMod, '{access-token}');// 某个access-token窗口
$redis = new Redis();
$redis->connect('192.168.10.5', 6379);
$redis->auth('rc_redis');
$redis->multi();
$redis->zRemRangeByLex($redisKey, '[0', '[' . ($now-$slidingWindow)); // 移除窗口外的数据
$redis->zrange($redisKey, 0, -1, true); // 获取窗口权重数据
$redis->zincrby($redisKey, 1, $now); // 增加权重
$redis->expire($redisKey, $slidingWindow);
$res = $redis->exec();
if (array_sum($res[1]) > $maximum) {
echo '超频', PHP_EOL;
}
思路二
- 以时间戳为有序集合的成员
- 每次请求,先使用
命令移除窗口外的成员ZREVRANGEBYSCORE
- 使用
命令获取有序集合的成员ZRANGE
- 使用
命令给有序集合增加成员zAdd
- 使用
命令重新设置有序集合有效期EXPIRE
- 计算获取到的成员数量,并判断是否超过阈值
PHP实现
$maximum = 10; // 最大请求数量
$slidingWindow = 10; // 滑动窗口大小(s)
$now = microtime(true);
$redisKeyMod = 'pre:sliding_window:sorted_sets:%s';
$redisKey = sprintf($redisKeyMod, 'test.com');// 全站窗口
//$redisKey = sprintf($redisKeyMod, '/api/test/info');// 某个接口窗口
//$redisKey = sprintf($redisKeyMod, '{access-token}');// 某个access-token窗口
$redis = new Redis();
$redis->connect('192.168.10.5', 6379);
$redis->auth('rc_redis');
$redis->multi();
$redis->zRemRangeByScore($redisKey, 0, $now-$slidingWindow); // 移除窗口外的数据
$redis->zrange($redisKey, 0, -1); // 获取窗口数据
$redis->zAdd($redisKey, $now, $now);
$redis->expire($redisKey, $slidingWindow);
$res = $redis->exec();
if (count($res[1]) > $maximum) {
echo '超频', PHP_EOL;
}