令牌桶限流(php redis)

在开发接口服务器的过程中,为了防止客户端对于接口的滥用,保护服务器的资源, 通常来说我们会对于服务器上的各种接口进行调用次数的限制。比如对于某个 用户,他在一个时间段(interval)内,比如 1 分钟,调用服务器接口的次数不能够 大于一个上限(limit),比如说 100 次。如果用户调用接口的次数超过上限的话,就直接拒绝用户的请求,返回错误信息。

服务接口的流量控制策略:分流、降级、限流等。本文讨论下限流策略,虽然降低了服务接口的访问频率和并发量,却换取服务接口和业务应用系统的高可用。

令牌桶算法(Token Bucket)和 Leaky Bucket 效果一样但方向相反的算法,更加容易理解.随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务.
令牌桶的另外一个好处是可以方便的改变速度. 一旦需要提高速率,则按需提高放入桶中的令牌的速率. 一般会定时(比如100毫秒)往桶中增加一定数量的令牌, 有些变种算法则实时的计算应该增加的令牌的数量.

class TrafficSahper{
 private $_config; // redis设定
 private $_redis;  // redis对象
 private $_queue;  // 令牌桶
 private $_max;    // 最大令牌
 public function __construct($config, $queue, $max){
    $this->_config = $config;
    $this->_queue = $queue;
    $this->_max = $max;
    $this->_redis = $this->connect();
}

    /*** 加入令牌 */
public function add($num=0){
    $curnum = intval($this->_redis->llen($this->_queue));
    $maxnum = intval($this->_max);
    $num = $maxnum>=$curnum+$num ? $num : $maxnum-$curnum;
    if($num>0){
            $token = array_fill(0, $num, 1);
            $this->_redis->lPush($this->_queue, ...$token);
            return $num;
        }
        return 0;
}

    public function get(){
        return $this->_redis->rpop($this->_queue) ? true : false;
   }

    public function connect(){
        try{
            $redis = new Redis();
            $redis->connect($this->_config['host'], $this->_config['port']);
            //echo $redis->ping();
        }catch(RedisException $e){
            var_dump($e);
        }
        return $redis;
    }
}
//new TrafficSahper();
?>


 require 'demo.php';
// // redis连接设定
$config = array(
    'host' => 'localhost',
    'port' => 6379,
);

// // 令牌桶容器
$queue = 'mycontainer';

// // 最大令牌数
 $max = 5;

// // 创建TrafficShaper对象
$oTrafficShaper = new TrafficSahper($config, $queue, $max);

//  // 重设令牌桶,填满令牌
 $oTrafficShaper->reset();

// // // 循环获取令牌,令牌桶内只有5个令牌,因此最后3次获取失败
 for($i=0; $i<8; $i++){
        var_dump($oTrafficShaper->get());
 }

//  // 加入10个令牌,最大令牌为5,因此只能加入5个
$add_num = $oTrafficShaper->add(10);
var_dump($add_num);

// // 循环获取令牌,令牌桶内只有5个令牌,因此最后1次获取失败
for($i=0; $i<15; $i++){
  var_dump($oTrafficShaper->get());
 }

crontab  -e  php路径  ( 加入定时任务执行php文件)

你可能感兴趣的:(令牌桶限流(php redis))