php+redis實現令牌桶演算法程式碼:
<?phpnamespace ApiLib;/** * 限流控制 */class RateLimit{ private $minNum = 60; //單個使用者每分存取數 private $dayNum = 10000; //單個使用者每天總的存取量 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' => '當前時刻令牌消耗完!']; } } 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; }}
程式碼要點:
1、首先定義規則
單個使用者每分鐘存取次數($minNum),單個使用者每天總的存取次數($dayNum),介面總的存取次數等不同的規則。
2、計算速率
該程式碼範例以秒為最小的時間單位,速率=存取次數/時間($initNum / $expire)
3、每次存取後補充的令牌個數計算方式
獲取上次存取的時間即上次存入令牌的時間,計算當前時刻與上次存取的時間差乘以速率就是此次需要補充的令牌個數,注意補充令牌後總的令牌個數不能大於初始化的令牌個數,以補充數和初始化數的最小值為準。
4、程式流程
第一次存取時初始化令牌個數($minNum),存入Redis同時將當前的時間戳存入以便計算下次需要補充的令牌個數。
第二次存取時獲取剩餘的令牌個數,並新增本次應該補充的令牌個數,補充後如何令牌數>0則當前存取是有效的可以存取,否則令牌使用完畢不可存取。先補充令牌再判斷令牌是否>0的原因是由於還有速率這個概念即如果上次剩餘的令牌為0但是本次應該補充的令牌>1那麼本次依然可以存取。
5、針對並行的處理
使用Redis的樂觀鎖機制。
更多相關知識,請關注 PHP中文網!!
以上就是令牌桶演算法如何使用php實現的詳細內容,更多請關注TW511.COM其它相關文章!