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;


     }
     

}
 

 

 

posted @ 2025-06-17 16:07  X__cicada  阅读(19)  评论(0)    收藏  举报