在开发接口服务器的过程中,为了防止客户端对于接口的滥用,保护服务器的资源,
通常来说我们会对于服务器上的各种接口进行调用次数的限制。比如对于某个 用户,他在一个时间段(interval)内,比如 1
分钟,调用服务器接口的次数不能够 大于一个上限(limit),比如说 100
次。如果用户调用接口的次数超过上限的话,就直接拒绝用户的请求,返回错误信息。
服务接口的流量控制策略:分流、降级、限流等。本文讨论下限流策略,虽然降低了服务接口的访问频率和并发量,却换取服务接口和业务应用系统的高可用。

令牌桶算法(Token Bucket)和 Leaky Bucket 效果一样但方向相反的算法,更加容易理解.随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务.

基础版

  1. 首先设有一个令牌桶,桶内存放令牌,一开始令牌桶内的令牌是满的(桶内令牌的数量可根据服务器情况设定)
  2. 每次访问从桶内取走一个令牌,当桶内令牌为0,则不允许再访问。
  3. 每隔一段时间,放入令牌,最多使桶内令牌满额。
class TrafficShaperControllerextends Controller
{/*** 令牌桶总数量*/private $totleNum = 25;/*** 令牌标识(可以根据需要加上关键ID,uid、orderid...)* @var string*/private $quekueName ="TrafficShaper_queue";/*** redis缓存类* @var object*/private $redis;/*** 初始化方法** @author heyw<1051834593@qq.com>* @since  2020/12/10*/public function _initialize(){$this->redis = Redis::getInstance();}/*** 模拟用户消耗令牌** @param int $num* @author heyw<1051834593@qq.com>* @since  2020/12/10*/public function run($num = 1){// 初始化$this->reset();// 模拟1s请求10次while (1) {$this->getKey();sleep(0.1);}}/***  获取令牌** @return bool* @author heyw<1051834593@qq.com>* @since  2020/12/11*/protected function getKey(){// 初始化$redis =$this->redis;$queueName =$this->quekueName;// 获取一个令牌,如果没有直接返回$res =$redis->rPop($queueName);// 获得令牌,处理业务var_dump($res ?'get it' :'empty');return true;}/*** 重置** @author heyw<1051834593@qq.com>* @since  2020/12/11*/protected function reset(){$this->redis->delete($this->quekueName);$this->add(25);}/*** 定时加入令牌桶,1s执行1次** @author heyw<1051834593@qq.com>* @since  2020/12/10*/public function add($stepNum = 5){// 初始化$redis      =$this->redis;$queueName  =$this->quekueName;// 当前令牌书$currNum    =$redis->lSize($queueName) ?: 0;$maxNum     =$this->totleNum;$addNum     =$maxNum >=$currNum +$stepNum ?$stepNum :$maxNum -$currNum;if ($addNum == 0) {return true;}// 加入令牌$token =array_fill(0,$addNum, 1);$redis->lPush($queueName,$token);return true;}
}

进阶版

<?php
namespace Api\Lib;/*** 限流控制*/
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:首先定义规则

单个用户每分钟访问次数
( m i n N u m ) , 单 个 用 户 每 天 总 的 访 问 次 数 ( minNum),单个用户每天总的访问次数( minNum),单个用户每天总的访问次数(dayNum),接口总的访问次数等不同的规则。

2:计算速率
该代码示例以秒为最小的时间单位,速率=访问次数/时间($initNum / $expire)

3:每次访问后补充的令牌个数计算方式
获取上次访问的时间即上次存入令牌的时间,计算当前时刻与上次访问的时间差乘以速率就是此次需要补充的令牌个数,注意补充令牌后总的令牌个数不能大于初始化的令牌个数,以补充数和初始化数的最小值为准。

4:程序流程
第一次访问时初始化令牌个数($minNum),存入Redis同时将当前的时间戳存入以便计算下次需要补充的令牌个数。第二次访问时获取剩余的令牌个数,并添加本次应该补充的令牌个数,补充后如何令牌数>0则当前访问是有效的可以访问,否则令牌使用完毕不可访问。先补充令牌再判断令牌是否>0的原因是由于还有速率这个概念即如果上次剩余的令牌为0但是本次应该补充的令牌>1那么本次依然可以访问。

PHP+Redis令牌桶算法 接口限流相关推荐

  1. 令牌桶算法和漏桶算法python_限流之漏桶算法与令牌桶算法

    在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流 缓存:缓存的目的是提升系统访问速度和增大系统处理容量 降级:降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降 ...

  2. 用令牌桶算法完成API接口限流

    这是张富涛的第15篇原创 用令牌桶算法完成API接口限流 本文介绍了"令牌桶算法",和使用lua+redis实现基于令牌桶算法的限流. 1. 限流需求的产生背景 软件开发时偶尔会面 ...

  3. java令牌_基于令牌桶算法的Java限流实现

    项目需要使用限流措施,查阅后主要使用令牌桶算法实现,为了更灵活的实现限流,就自己实现了一个简单的基于令牌桶算法的限流实现. 令牌桶算法描述 令牌桶这种控制机制基于令牌桶中是否存在令牌来指示什么时候可以 ...

  4. java同名过滤器_Gateway Redis令牌桶请求限流过滤器

    spring cloud gateway默认基于redis令牌桶算法进行微服务的限流保护,采用RateLimter限流算法来实现. 1.引入依赖包 org.springframework.cloud ...

  5. 接口限流、服务降级、熔断

    接口限流 为什么需要限流 与用户打交道的服务 比如web服务.对外API,这种类型的服务有以下几种可能导致机器被拖垮 用户增长过快(这是好事) 因为某个热点事件(微博热搜) 竞争对象爬虫 恶意的刷单 ...

  6. 接口限流算法:漏桶算法令牌桶算法

    工作中对外提供的API 接口设计都要考虑限流,如果不考虑限流,会成系统的连锁反应,轻者响应缓慢,重者系统宕机,整个业务线崩溃,如何应对这种情况呢,我们可以对请求进行引流或者直接拒绝等操作,保持系统的可 ...

  7. 十三水算法php_基于PHP+Redis令牌桶限流

    一 .场景描述 在开发接口服务器的过程中,为了防止客户端对于接口的滥用,保护服务器的资源, 通常来说我们会对于服务器上的各种接口进行调用次数的限制.比如对于某个 用户,他在一个时间段(interval ...

  8. 使用令牌桶算法解决调用第三方接口限流问题

    我们在调用第三方接口时常常会碰到接口限流问题,为了解决这一问题,大家想出了许多方法.我这里介绍一下我的方法,第三方接口限流一般是基于令牌桶算法的,那么我们可以以彼之道还治彼身,使用令牌桶算法实现我方调 ...

  9. 接口限流算法:漏桶算法amp;令牌桶算法

    转载自 接口限流算法:漏桶算法&令牌桶算法 背景 每一个对外提供的API接口都是需要做流量控制的,不然会导致系统直接崩溃.很简单的例子,和保险丝的原理一样,如果用电符合超载就会烧断保险丝断掉电 ...

最新文章

  1. 子div超出父div_菜鸟学 react props 子到父
  2. BS-XX-020基于SSM实现停车位租赁系统
  3. 用户请求队列化_分布式消息队列选型分析
  4. python数组去重函数_Python常用功能函数系列总结(一)
  5. UNITY2018开启deepprofiling
  6. 区块链及比特币入门指南
  7. 关于Java的23种设计模式的有趣见解
  8. Jenkins集成java非maven/ant项目的打包思路
  9. 1.3、TetGen网格化过程之描述
  10. ISO9001 试题及答案
  11. 基于Levy飞行策略的改进樽海鞘群算法( LECUSSA) Matlab代码
  12. java mars2_Mars-java 2.1.5 发布
  13. Windows 10 无法设置代理
  14. Java并发机制的底层实现原理--volatile
  15. pc机属于模拟专用微型计算机,《春11计算机基础》期末试题
  16. php上传二进制数据流
  17. 关于ExecuteNonQuery()执行成功却返回-1的问题
  18. radisys官方介绍--Promentum ATCA-1200== ATCA 可控 4-AMC 刀片式载板
  19. 李开复给中国大学生的第三封信——成功、自信、快乐
  20. time(),date(),microtime()…

热门文章

  1. Mysql 中的各种“删除”。删除数据库、删除表、删除字段
  2. 常见服务器返回状态码
  3. MAC地址的介绍(单播、广播、组播、数据收发)
  4. WLAN@Wi-Fi
  5. 细粒度图像分类论文研读-2011
  6. 微信小游戏客户端开发环境搭建
  7. 两轮换电领域的“苹果”,“换换”能成吗?
  8. 文献阅读笔记:Unsupervised Machine Translation Using Monolingual Corpora Only
  9. html 文本换行 \n 不换行 空格无效
  10. 软技能:代码之外的生存指南