最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當(dāng)前位置: 首頁 - 科技 - 知識(shí)百科 - 正文

令牌桶算法如何使用php實(shí)現(xiàn)

來源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-03 13:38:35
文檔

令牌桶算法如何使用php實(shí)現(xiàn)

令牌桶算法如何使用php實(shí)現(xiàn):php+redis實(shí)現(xiàn)令牌桶算法代碼:<phpnamespace Api\Lib;/** * 限流控制 */class RateLimit{ private $minNum = 60; //單個(gè)用戶每分訪問數(shù) private $dayNum = 10000; //單個(gè)用戶每天總的訪問量 public function minL
推薦度:
導(dǎo)讀令牌桶算法如何使用php實(shí)現(xiàn):php+redis實(shí)現(xiàn)令牌桶算法代碼:<phpnamespace Api\Lib;/** * 限流控制 */class RateLimit{ private $minNum = 60; //單個(gè)用戶每分訪問數(shù) private $dayNum = 10000; //單個(gè)用戶每天總的訪問量 public function minL

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

文檔

令牌桶算法如何使用php實(shí)現(xiàn)

令牌桶算法如何使用php實(shí)現(xiàn):php+redis實(shí)現(xiàn)令牌桶算法代碼:<phpnamespace Api\Lib;/** * 限流控制 */class RateLimit{ private $minNum = 60; //單個(gè)用戶每分訪問數(shù) private $dayNum = 10000; //單個(gè)用戶每天總的訪問量 public function minL
推薦度:
標(biāo)簽: php 實(shí)現(xiàn) 令牌
  • 熱門焦點(diǎn)

最新推薦

猜你喜歡

熱門推薦

專題
Top