1.首先设有一个令牌桶,桶内存放令牌,一开始令牌桶内的令牌是满的(桶内令牌的数量可根据服务器情况设定)。

2.每次访问从桶内取走一个令牌,当桶内令牌为0,则不允许再访问。

3.每隔一段时间,再放入令牌,最多使桶内令牌满额。(可以根据实际情况,每隔一段时间放入若干个令牌,或直接补满令牌桶)我们可以使用redis的队列作为令牌桶容器使用,使用lPush(入队),rPop(出队),实现令牌加入与消耗的操作。

4.令牌桶的另外一个好处是可以方便的改变速度. 一旦需要提高速率,则按需提高放入桶中的令牌的速率. 一般会定时(比如100毫秒)往桶中增加一定数量的令牌, 有些变种算法则实时的计算应该增加的令牌的数量.


<?php
 
class Token
{
    private $_max;
    private $_queue;
    private $_redis;
 
    public function __construct()
    {
        try {
            $this->_redis = new \Redis();
            $this->_redis->connect('127.0.0.1', 6379);
            $this->_queue = 'token';
            $this->_max = 10;
        } catch (RedisException $exception) {
            throw new Exception($exception->__toString());
            return false;
        }
 
    }
 
    /**
     * 令牌初始化
     */
    public function reset()
    {
        $this->_redis->del($this->_queue);
        $this->add($this->_max);
    }
 
    /**
     * 添加令牌
     * @param int $number
     */
    public function add($number = 1)
    {
        $maxNumber = $this->_max;
        $currentNumber = $this->_redis->lLen($this->_queue);
        $number = $maxNumber >= ($currentNumber + $number) ? $number : ($maxNumber - $currentNumber);
        if ($number > 0) {
            $tokens = array_fill(0, $number, 1);
            foreach ($tokens as $token) {
                $this->_redis->lPush($this->_queue, $token);
            }
        }
 
    }
 
    /**
     * 获取令牌
     */
    public function get()
    {
        return $this->_redis->rPop($this->_queue) ? true : false;
    }
}
Last modification:May 12, 2021
如果觉得我的文章对你有用,请随意赞赏