php api限流可通过五种方法实现:一、令牌桶算法(redis键rate_limit:{user_id}:{api_path});二、漏桶算法(redis列表存时间戳);三、滑动窗口日志(sorted set精确计时);四、swoole协程内存限流(共享数组);五、laravel中间件集成(cache驱动)。

如果您在使用PHP框架开发API服务时,发现接口请求量突增导致服务器响应变慢或崩溃,则可能是缺乏有效的请求限流机制。以下是实现接口限流的具体方法:
一、令牌桶算法实现
令牌桶算法通过以固定速率向桶中添加令牌,每个请求需消耗一个令牌,若桶中无令牌则拒绝请求。该方式支持突发流量,平滑控制请求速率。
1、定义一个Redis键作为令牌桶,键名为rate_limit:{user_id}:{api_path}。
2、每次请求前,使用Redis的INCR命令增加计数器,并用EXPIRE设置过期时间为窗口周期(如60秒)。
立即学习“PHP免费学习笔记(深入)”;
3、获取当前桶内令牌数,若小于等于0,执行PTTL检查剩余存活时间,若存在且大于0,则拒绝请求并返回HTTP 429状态码。
4、若令牌数大于0,使用DECR消耗一个令牌,并允许请求继续处理。
二、漏桶算法实现
漏桶算法将请求视为水滴注入固定容量的桶中,桶以恒定速率“漏水”,超容则丢弃请求。该方式严格限制平均请求速率,适用于对稳定性要求极高的场景。
1、在Redis中为每个客户端维护一个列表结构,存储其最近请求的时间戳,键名为leaky_bucket:{client_ip}:{api_path}。
2、请求到达时,使用LRANGE获取过去窗口时间内所有时间戳(如最近10次请求),过滤掉早于当前时间减去窗口时长的记录。
3、若剩余请求数已达阈值(如每秒10次),则拒绝本次请求。
4、将当前请求时间戳通过LPUSH推入列表,并用LTRIM截取最新N条记录,确保列表长度不超过阈值。
三、滑动窗口日志算法实现
滑动窗口日志通过记录每个请求的精确时间戳,在每次请求时动态计算当前窗口内请求数,精度高但存储开销较大。
1、使用Redis的Sorted Set结构,以请求时间戳为score,唯一请求ID为member,键名为sliding_log:{api_path}。
2、请求到来时,调用ZCOUNT统计当前时间往前推窗口时长(如1分钟)内的成员数量。
3、若数量超过设定阈值,则返回<strong><font color="green">HTTP 429 Too Many Requests</font></strong>并中断处理。
4、调用ZADD插入当前请求时间戳,并用ZREMRANGEBYSCORE清理过期时间戳,保持集合仅含有效窗口数据。
四、基于Swoole协程的内存限流中间件
在Swoole常驻内存环境下,可利用协程共享内存变量实现轻量级限流,避免Redis网络开销,适合单机高并发场景。
1、在Server启动时,初始化一个全局协程安全的数组$this->limiters,键为{api_path}:{client_ip},值为包含count和last_time的结构体。
2、请求进入中间件后,获取当前时间戳,检查该键是否存在且未超时(如1秒窗口)。
3、若存在且count小于阈值,则递增count;否则拒绝请求并设置响应头X-RateLimit-Remaining: 0。
4、若键不存在或已超时,重置为count = 1、last_time = now,并允许通过。
五、Laravel框架中间件集成方案
Laravel可通过自定义中间件结合缓存驱动实现灵活限流,支持按用户、IP或路由分组控制。
1、运行php artisan make:middleware RateLimiterMiddleware创建中间件类。
2、在handle()方法中,构造缓存键rate_limit_ . $request->ip() . '_' . $request->route()->getName()。
3、使用Cache::add($key, 0, 60)初始化计数器(仅首次成功),再用Cache::increment($key)累加。
4、判断返回值是否超过阈值,若超出则抛出<strong><font color="green">Illuminate\Http\Exceptions\ThrottleRequestsException</font></strong>,由框架自动返回429响应。











