nginx服务器限流

    1. 该模块可以指定会话请求数量,可以通过指定 ip 进行请求频率限制。使用漏桶算法进行请求频率限制。
    2. http {
    3. //会话状态存储在了10m的名称为"one"这个区域。该区域平均查询限制在每秒1个请求
    4. limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
    5. ... server { ... location /search/ {
    6. // 每秒平均请求不超过1个请求 突发不超过5个查询 如果不需要限制突发延迟内的超额请求,则应使用
    7. nodelay limit_req zone=one burst= 5 nodelay;
    8. }

    php+redis 实现漏桶算法限流类
    漏桶算法
    描述:
    当前水量:上次容量 - 流出容量 + 注入水量
    流出容量:(当前注水时间 - 上次注水时间)* 流出速率
    1644569487(1).jpg
    实现方法
    新增 BucketLimit.php 类

    1. protected $capacity = 60; //桶子总容量
    2. protected $addNum = 20; //每次注入水的容量
    3. protected $rate = 2; //漏水速率
    4. protected $water_key = "water_capacity"; //缓存key
    5. public $redis; //使用redis 缓存当前桶水量和上次注水时间
    6. public function __construct()
    7. {
    8. $redis = new \Redis();
    9. $this->redis= $redis;
    10. $this->redis->connect('127.0.0.1',6379);
    11. }

    实现方法

    1. /**
    2. * @param $api [string 指定接口限流]
    3. * @param $addNum [int 注水量 ]
    4. * @return bool
    5. */
    6. public function bucket($addNum,$api='')
    7. {
    8. $this->addNum = $addNum;
    9. // 获取上次 桶内水量 注水时间
    10. list($waterCapacity,$waterTime,$lastTime) = $this->getLastWater();
    11. //计算出时间内流出的水量
    12. $lastWater = ($lastTime-$waterTime)*$this->rate;
    13. //本次水量
    14. $waterCapacity = $waterCapacity-$lastWater;
    15. //水量不能小于0
    16. $waterCapacity = ( $waterCapacity>=0 ) ? $waterCapacity : 0 ;
    17. $waterTime = $lastTime;
    18. //当前水量大于桶子容量 溢出返回 false 存储水量和注水时间
    19. if( ($waterCapacity+$addNum) <= $this->capacity ){
    20. $waterCapacity += $addNum;
    21. $this->setWater($waterCapacity,$waterTime);
    22. return true;
    23. }else{
    24. $this->setWater($waterCapacity,$waterTime);
    25. return false;
    26. }
    27. }
    28. /**
    29. * @return array [$waterCapacity,$waterTime,$lastTime] * 当前容量 上次漏水时间 当前时间
    30. */
    31. private function getLastWater()
    32. {
    33. $water = $this->redis->get($this->water_key);
    34. if($water) {
    35. $water = json_decode($water,true);
    36. $waterCapacity =$water['water_capacity']; //上一次容量
    37. $waterTime =$water['time']; //上一次注水时间
    38. $lastTime = time(); //本次注水时间
    39. } else{
    40. $this->redis->set($this->water_key,json_encode([
    41. 'water_capacity'=>0,
    42. 'time'=>time()
    43. ]));
    44. $waterCapacity =0; //上一次容量
    45. $waterTime =time(); //上一次注水时间
    46. $lastTime = time(); //本次注水时间
    47. }
    48. return [$waterCapacity,$waterTime,$lastTime];
    49. }
    50. /**
    51. * @param $waterCapacity [int 本次剩余容量]
    52. * @param $waterTime [int 本次注水时间]
    53. */
    54. private function setWater($waterCapacity,$waterTime)
    55. {
    56. $this->redis->set($this->water_key,json_encode([
    57. 'water_capacity'=>$waterCapacity,
    58. 'time'=>$waterTime
    59. ]));
    60. }

    测试

    1. require_once 'BucketLimit.php';
    2. $bucket = new BucketLimit();
    3. for($i=1;$i<=100;$i++) {
    4. //根据for + sleep函数模拟请求 正常2s请求一次 方法正常不限流 sleep(1);
    5. $data = $bucket->bucket(10);
    6. var_dump($data)."\n";
    7. }

    令牌算法

    https://learnku.com/articles/60337