nginx服务器限流
该模块可以指定会话请求数量,可以通过指定 ip 进行请求频率限制。使用漏桶算法进行请求频率限制。http {//会话状态存储在了10m的名称为"one"这个区域。该区域平均查询限制在每秒1个请求limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;... server { ... location /search/ {// 每秒平均请求不超过1个请求 突发不超过5个查询 如果不需要限制突发延迟内的超额请求,则应使用nodelay limit_req zone=one burst= 5 nodelay;}
php+redis 实现漏桶算法限流类
漏桶算法
描述:
当前水量:上次容量 - 流出容量 + 注入水量
流出容量:(当前注水时间 - 上次注水时间)* 流出速率
实现方法
新增 BucketLimit.php 类
protected $capacity = 60; //桶子总容量protected $addNum = 20; //每次注入水的容量protected $rate = 2; //漏水速率protected $water_key = "water_capacity"; //缓存keypublic $redis; //使用redis 缓存当前桶水量和上次注水时间public function __construct(){$redis = new \Redis();$this->redis= $redis;$this->redis->connect('127.0.0.1',6379);}
实现方法
/*** @param $api [string 指定接口限流]* @param $addNum [int 注水量 ]* @return bool*/public function bucket($addNum,$api=''){$this->addNum = $addNum;// 获取上次 桶内水量 注水时间list($waterCapacity,$waterTime,$lastTime) = $this->getLastWater();//计算出时间内流出的水量$lastWater = ($lastTime-$waterTime)*$this->rate;//本次水量$waterCapacity = $waterCapacity-$lastWater;//水量不能小于0$waterCapacity = ( $waterCapacity>=0 ) ? $waterCapacity : 0 ;$waterTime = $lastTime;//当前水量大于桶子容量 溢出返回 false 存储水量和注水时间if( ($waterCapacity+$addNum) <= $this->capacity ){$waterCapacity += $addNum;$this->setWater($waterCapacity,$waterTime);return true;}else{$this->setWater($waterCapacity,$waterTime);return false;}}/*** @return array [$waterCapacity,$waterTime,$lastTime] * 当前容量 上次漏水时间 当前时间*/private function getLastWater(){$water = $this->redis->get($this->water_key);if($water) {$water = json_decode($water,true);$waterCapacity =$water['water_capacity']; //上一次容量$waterTime =$water['time']; //上一次注水时间$lastTime = time(); //本次注水时间} else{$this->redis->set($this->water_key,json_encode(['water_capacity'=>0,'time'=>time()]));$waterCapacity =0; //上一次容量$waterTime =time(); //上一次注水时间$lastTime = time(); //本次注水时间}return [$waterCapacity,$waterTime,$lastTime];}/*** @param $waterCapacity [int 本次剩余容量]* @param $waterTime [int 本次注水时间]*/private function setWater($waterCapacity,$waterTime){$this->redis->set($this->water_key,json_encode(['water_capacity'=>$waterCapacity,'time'=>$waterTime]));}
测试
require_once 'BucketLimit.php';$bucket = new BucketLimit();for($i=1;$i<=100;$i++) {//根据for + sleep函数模拟请求 正常2s请求一次 方法正常不限流 sleep(1);$data = $bucket->bucket(10);var_dump($data)."\n";}
令牌算法
