php+redis實(shí)現(xiàn)令牌桶算法代碼:
<?phpnamespace ApiLib;/** * 限流控制 */class RateLimit{ private $minNum = 60; //單個(gè)用戶每分訪問數(shù) private $dayNum = 10000; //單個(gè)用戶每天總的訪問量 public function minLimit($uid) { $minNumKey = $uid . '_minNum'; $dayNumKey = $uid . '_dayNum'; $resMin = $this->getRedis($minNumKey, $this->minNum, 60); $resDay = $this->getRedis($minNumKey, $this->minNum, 86400); if (!$resMin['status'] || !$resDay['status']) { exit($resMin['msg'] . $resDay['msg']); } } public function getRedis($key, $initNum, $expire) { $nowtime = time(); $result = ['status' => true, 'msg' => '']; $redisObj = $this->di->get('redis'); $redis->watch($key); $limitVal = $redis->get($key); if ($limitVal) { $limitVal = json_decode($limitVal, true); $newNum = min($initNum, ($limitVal['num'] - 1) + (($initNum / $expire) * ($nowtime - $limitVal['time']))); if ($newNum > 0) { $redisVal = json_encode(['num' => $newNum, 'time' => time()]); } else { return ['status' => false, 'msg' => '當(dāng)前時(shí)刻令牌消耗完!']; } } else { $redisVal = json_encode(['num' => $initNum, 'time' => time()]); } $redis->multi(); $redis->set($key, $redisVal); $rob_result = $redis->exec(); if (!$rob_result) { $result = ['status' => false, 'msg' => '訪問頻次過多!']; } return $result; }}
代碼要點(diǎn):
1、首先定義規(guī)則
單個(gè)用戶每分鐘訪問次數(shù)($minNum),單個(gè)用戶每天總的訪問次數(shù)($dayNum),接口總的訪問次數(shù)等不同的規(guī)則。
2、計(jì)算速率
該代碼示例以秒為最小的時(shí)間單位,速率=訪問次數(shù)/時(shí)間($initNum / $expire)
3、每次訪問后補(bǔ)充的令牌個(gè)數(shù)計(jì)算方式
獲取上次訪問的時(shí)間即上次存入令牌的時(shí)間,計(jì)算當(dāng)前時(shí)刻與上次訪問的時(shí)間差乘以速率就是此次需要補(bǔ)充的令牌個(gè)數(shù),注意補(bǔ)充令牌后總的令牌個(gè)數(shù)不能大于初始化的令牌個(gè)數(shù),以補(bǔ)充數(shù)和初始化數(shù)的最小值為準(zhǔn)。
4、程序流程
第一次訪問時(shí)初始化令牌個(gè)數(shù)($minNum),存入Redis同時(shí)將當(dāng)前的時(shí)間戳存入以便計(jì)算下次需要補(bǔ)充的令牌個(gè)數(shù)。
第二次訪問時(shí)獲取剩余的令牌個(gè)數(shù),并添加本次應(yīng)該補(bǔ)充的令牌個(gè)數(shù),補(bǔ)充后如何令牌數(shù)>0則當(dāng)前訪問是有效的可以訪問,否則令牌使用完畢不可訪問。先補(bǔ)充令牌再判斷令牌是否>0的原因是由于還有速率這個(gè)概念即如果上次剩余的令牌為0但是本次應(yīng)該補(bǔ)充的令牌>1那么本次依然可以訪問。
5、針對并發(fā)的處理
使用Redis的樂觀鎖機(jī)制。
更多相關(guān)知識(shí),請關(guān)注 PHP中文網(wǎng)?。?/p>
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com