首頁 >後端開發 >PHP問題 >令牌桶演算法如何使用php實現

令牌桶演算法如何使用php實現

尚
原創
2020-04-25 11:26:463229瀏覽

令牌桶演算法如何使用php實現

php redis實作令牌桶演算法程式碼:

<?phpnamespace Api\Lib;/**
 * 限流控制
 */class RateLimit{
    private $minNum = 60; //单个用户每分访问数
    private $dayNum = 10000; //单个用户每天总的访问量

    public function minLimit($uid)
    {
        $minNumKey = $uid . &#39;_minNum&#39;;
        $dayNumKey = $uid . &#39;_dayNum&#39;;
        $resMin    = $this->getRedis($minNumKey, $this->minNum, 60);
        $resDay    = $this->getRedis($minNumKey, $this->minNum, 86400);
        if (!$resMin[&#39;status&#39;] || !$resDay[&#39;status&#39;]) {
            exit($resMin[&#39;msg&#39;] . $resDay[&#39;msg&#39;]);
        }
    }

    public function getRedis($key, $initNum, $expire)
    {
        $nowtime  = time();
        $result   = [&#39;status&#39; => true, &#39;msg&#39; => &#39;&#39;];
        $redisObj = $this->di->get(&#39;redis&#39;);
        $redis->watch($key);
        $limitVal = $redis->get($key);
        if ($limitVal) {
            $limitVal = json_decode($limitVal, true);
            $newNum   = min($initNum, ($limitVal[&#39;num&#39;] - 1) + (($initNum / $expire) * ($nowtime - $limitVal[&#39;time&#39;])));
            if ($newNum > 0) {
                $redisVal = json_encode([&#39;num&#39; => $newNum, &#39;time&#39; => time()]);
            } else {
                return [&#39;status&#39; => false, &#39;msg&#39; => &#39;当前时刻令牌消耗完!&#39;];
            }
        } else {
            $redisVal = json_encode([&#39;num&#39; => $initNum, &#39;time&#39; => time()]);
        }
        $redis->multi();
        $redis->set($key, $redisVal);
        $rob_result = $redis->exec();
        if (!$rob_result) {
            $result = [&#39;status&#39; => false, &#39;msg&#39; => &#39;访问频次过多!&#39;];
        }
        return $result;
    }}

程式碼重點:

1、先定義規則

#單一用戶每分鐘造訪次數($minNum),單一使用者每天總的造訪次數($dayNum),介面總的造訪次數等不同的規則。

2、計算速率

此程式碼範例以秒為最小的時間單位,速率=造訪次數/時間($initNum / $expire)

3、每次訪問後補充的令牌個數計算方式

取得上次造訪的時間即上次存入令牌的時間,計算當前時刻與上次造訪的時間差乘以速率就是此次需要補充的令牌個數,注意補充令牌後總的令牌個數不能大於初始化的令牌個數,以補充數和初始化數的最小值為準。

4、程式流程

第一次造訪時初始化令牌個數($minNum),存入Redis同時將當前的時間戳記存入以便計算下次需要補充的命令牌個數。

第二次訪問時獲取剩餘的令牌個數,並添加本次應該補充的令牌個數,補充後如何令牌數>0則當前訪問是有效的可以訪問,否則令牌使用完畢不可訪問。先補充令牌再判斷令牌是否>0的原因是由於還有速率這個概念即如果上次剩餘的令牌為0但是本次應該補充的令牌>1那麼本次依然可以存取。

5、針對並發的處理

使用Redis的樂觀鎖定機制。

更多相關知識,請追蹤 PHP中文網! !

以上是令牌桶演算法如何使用php實現的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn