【PHP】php 基于redis使用令牌桶算法实现流量控制

整理自:

https://www.cnblogs.com/itbsl/p/13407489.html

https://www.cnblogs.com/myJuly/p/13608475.html

https://mp.weixin.qq.com/s/JQYWVL2YUKLiVZfV99z4cg

如果有侵权请联系删除

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

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

  3. 每隔一段时间,放入令牌,最多使桶内令牌满额。

class TrafficShaperController extends Controller
{

    /**
     * 令牌桶总数量
     * @var int
     */
    private $totleNum = 25;

    /**
     * 令牌标识(可以根据需要加上关键ID,uid、orderid...)
     * @var string
     */
    private $quekueName ="TrafficShaper_queue";

    /**
     * redis缓存类
     * @var object
     */
    private $redis;

    /**
     * 初始化方法
     *
     * @author heyw<1051834593@qq.com>
     * @since  2020/12/10
     */
    public function _initialize()
    {
        $this->redis = Redis::getInstance();
    }

    /**
     * 模拟用户消耗令牌
     *
     * @param int $num
     * @author heyw<1051834593@qq.com>
     * @since  2020/12/10
     */
    public function run($num = 1)
    {
        // 初始化
        $this->reset();

        // 模拟1s请求10次
        while (1) {
            $this->getKey();
            sleep(0.1);
        }
    }

    /**
     *  获取令牌
     *
     * @return bool
     * @author heyw<1051834593@qq.com>
     * @since  2020/12/11
     */
    protected function getKey()
    {
        // 初始化
        $redis = $this->redis;
        $queueName = $this->quekueName;

        // 获取一个令牌,如果没有直接返回
        $res = $redis->rPop($queueName);

        // 获得令牌,处理业务
        var_dump($res ?'get it' : 'empty');

        return true;
    }

    /**
     * 重置
     *
     * @author heyw<1051834593@qq.com>
     * @since  2020/12/11
     */
    protected function reset()
    {
        $this->redis->delete($this->quekueName);
        $this->add(25);
    }

    /**
     * 定时加入令牌桶,1s执行1次
     *
     * @author heyw<1051834593@qq.com>
     * @since  2020/12/10
     */
    public function add($stepNum = 5)
    {
        // 初始化
        $redis      = $this->redis;
        $queueName  = $this->quekueName;

        // 当前令牌书
        $currNum    = $redis->lSize($queueName) ?: 0;
        $maxNum     = $this->totleNum;
        $addNum     = $maxNum >= $currNum + $stepNum ? $stepNum : $maxNum - $currNum;
        if ($addNum == 0) {
            return true;
        }

        // 加入令牌
        $token = array_fill(0, $addNum, 1);
        $redis->lPush($queueName, $token);

        return true;
    }
}

  

 

posted @ 2020-12-24 16:20  蓝色星辰1993  阅读(393)  评论(0编辑  收藏  举报