PHP限流算法
一.限流算法总览:
| 类别 | 名称 | 是否常用 | 特点说明 |
| 固定窗口 | Fixed Window | 常用 | 简单实现,时间窗口对齐,有突刺风险 |
| 滑动窗口类 |
Sliding Log Window Sliding Window Counter |
不常用 常用 |
精准记录每次请求时间,性能差 折中方案,统计多个窗口,平滑但实现简单 |
| 令牌桶类 | Token Buket | 常用 | 控制速度 Rate 允许突发 |
| 漏桶类 | Leaky Bucket | 常用 | 控制速率,不允许突发,流速恒定 |
| 并发控制类 | Semaphore限流 | 常用 | 控制并发数,而非速率(如最多同时处理N个) |
二.常用限流算法详解
1.标准的固定窗口限流
- 把时间划分成固定窗口(如每分钟一个窗口),窗口内计数不超过阈值
- 使用简单,适合大多数业务.
- 缺点:存在"突刺"问题 (如59s发100次+ 60s又发100次)
- 实现: Redis incr + expire
<?php class FixedWindowLimiter { private $redis; private $limit = 100; private $interval = 60; public function __construct() { $this->redis = new Redis(); $this->redis->connect('127.0.0.1',6379); } //普通redis public function allow($userId){ $now = time(); $windowStart = floor($now/$this->interval) * $this->interval; $key = "rate_limit:{$userId}:{$windowStart}"; $count = $this->redis->incr($key); if($count == 1){ $this->redis->expire($key,$this->interval +1); } if($count > $this->limit){ return false; } return true; } //加lua脚本的 public function luaAllow($userId){ $now = time(); $windowStart = floor($now/$this->interval) * $this->interval; $key = "rate_limit:{$userId}:{$windowStart}"; $luaScript = <<<LUA local current = redis.call("incr",KEYS[1]) if current == 1 then redis.call("expire",KEY[1],ARGV[1]) end return current LUA; $count = $this->redis->eval($luaScript,[$key,$this->interval +1],1); return $count<= $this->limit; } }

浙公网安备 33010602011771号