开启掘金成长之旅!这是我参与「掘金日新计划 · 6 月更文挑战」的第 6 天,点击查看活动详情
什么是接口限流
那么什么是限流呢?顾名思义,限流就是限制流量,包括并发的流量和一定时间内的总流量,就像你宽带包了1个G的流量,用完了就没了,所以控制你的使用频率和单次使用的总消耗。
通过限流,我们可以很好地控制系统的qps,从而达到保护系统或者接口服务器稳定的目的。 接口限流的常用算法
1.固定窗口计数器(Fixed Window Counter):该方案将请求计数器与固定时间窗口结合。例如,你可以在每分钟内限制API调用次数为100次。如果超过该限制,则拒绝进一步的请求。这种方法简单直观,但可能会导致请求在时间窗口的开始瞬间发生突发。
2.滑动窗口计数器(Sliding Window Counter):该方案与固定窗口计数器类似,但请求计数器会在整个时间窗口内移动。例如,你可以设置每分钟最多100次的请求,但在每秒钟内的最大请求数不超过窗口大小除以60。这种方法可以更平滑地限制流量,但实现稍微复杂一些。
3.令牌桶算法(Token Bucket Algorithm):该算法基于一个令牌桶,其中包含固定数量的令牌。每当有请求到达时,就会从桶中获取一个令牌。如果桶中没有足够的令牌,则请求被拒绝。令牌按照一定的速率定期被添加到桶中,以控制请求的速率。这种方法可以更灵活地应对突发流量。
具体实例
<?php
class RateLimiter {
private $redis; // Redis连接
public function __construct() {
// 假设已经建立了与Redis的连接
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
public function limitRequests($key, $limit, $window) {
$currentTime = time();
$keyPrefix = 'ratelimiter:' . $key;
$windowKey = $keyPrefix . ':' . floor($currentTime / $window);
$requests = $this->redis->get($windowKey);
if ($requests === false) {
// 创建新的窗口
$this->redis->multi();
$this->redis->incr($windowKey);
$this->redis->expire($windowKey, $window + 1); // 设置过期时间略大于窗口大小
$this->redis->exec();
return true;
}
if ($requests < $limit) {
// 在当前窗口内的请求数量未达到限制
$this->redis->incr($windowKey);
return true;
}
// 达到限制,拒绝请求
return false;
}
}
// 使用示例
$rateLimiter = new RateLimiter();
// API限流,限制每分钟最多5次请求
$key = 'api:example';
$limit = 5;
$window = 60;
if ($rateLimiter->limitRequests($key, $limit, $window)) {
// 执行API逻辑
echo "API请求成功";
} else {
// 返回请求频率过高的错误信息
echo "请求频率过高,请稍后再试";
}
?>