视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
令牌桶算法如何使用php实现
2020-11-03 13:38:35 责编:小采
文档


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, 800);
 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中文网!!

下载本文
显示全文
专题