PHPAPI限流与频率控制API限流是保护后端服务的重要手段。防止接口被过度调用导致服务不可用。今天说说PHP中各种限流算法的实现。计数器限流最简单的实现。phpclass RateLimiter{private Redis $redis;private int $maxRequests;private int $window;public function __construct(Redis $redis, int $maxRequests 100, int $window 60){$this-redis $redis;$this-maxRequests $maxRequests;$this-window $window;}public function allow(string $key): bool{$current $this-redis-get($key);if ($current ! false $current $this-maxRequests) {return false;}if ($current false) {$this-redis-setex($key, $this-window, 1);} else {$this-redis-incr($key);}return true;}public function getRemaining(string $key): int{$current (int)$this-redis-get($key);return max(0, $this-maxRequests - $current);}public function reset(string $key): void{$this-redis-del($key);}}$limiter new RateLimiter(new Redis());$clientIp $_SERVER[REMOTE_ADDR] ?? 127.0.0.1;if (!$limiter-allow(api:{$clientIp})) {http_response_code(429);echo json_encode([error 请求过于频繁]);exit;}echo json_encode([status ok, remaining $limiter-getRemaining(api:{$clientIp})]);?令牌桶限流算法。phpclass TokenBucket{private Redis $redis;private int $capacity;private int $rate;public function __construct(Redis $redis, string $key, int $capacity 100, int $rate 10){$this-redis $redis;$this-key bucket:{$key};$this-capacity $capacity;$this-rate $rate;}public function allow(int $cost 1): bool{$this-refill();$tokens $this-redis-decrBy($this-key, $cost);return $tokens 0;}private function refill(): void{$script local key KEYS[1]local capacity tonumber(ARGV[1])local rate tonumber(ARGV[2])local now tonumber(ARGV[3])local ttl redis.call(TTL, key)if ttl 0 thenredis.call(SET, key, capacity, EX, 60)return capacityendlocal tokens tonumber(redis.call(GET, key)) or capacitylocal lastRefill tonumber(redis.call(GET, key .. :time)) or nowlocal elapsed now - lastRefilllocal newTokens math.floor(elapsed * rate / 60)if newTokens 0 thentokens math.min(capacity, tokens newTokens)redis.call(SET, key, tokens)redis.call(SET, key .. :time, now)endreturn tokens;$this-redis-eval($script, [$this-key, $this-capacity, $this-rate, time()], 1);}}?滑动窗口限流。phpclass SlidingWindow{private Redis $redis;private string $key;private int $limit;private int $window;public function __construct(Redis $redis, string $key, int $limit 100, int $window 60){$this-redis $redis;$this-key sw:{$key};$this-limit $limit;$this-window $window;}public function allow(): bool{$now microtime(true);$windowStart $now - $this-window;$this-redis-zRemRangeByScore($this-key, 0, $windowStart);$current $this-redis-zCard($this-key);if ($current $this-limit) return false;$this-redis-zAdd($this-key, $now, (string)$now);$this-redis-expire($this-key, $this-window 1);return true;}public function getRemaining(): int{$now microtime(true);$windowStart $now - $this-window;$this-redis-zRemRangeByScore($this-key, 0, $windowStart);return max(0, $this-limit - $this-redis-zCard($this-key));}}?API限流是保护后端的重要措施。计数器简单但精度不够令牌桶允许突发流量滑动窗口精度高。选择合适的限流算法根据业务需求来定对外的API用严格限流内部服务可以用宽松限流。