高可用对于一个应用和API接口是至关重要的。如果我们提供一个接口,突然面临流量爆发式增长,对于这种情况,不仅会影响网站的访问速度,甚至可能会导致服务器崩溃,使得所有用户都无法正常访问。

对于这种情况,有的同学认为:“我们可以通过提高配置或者增加机器去解决这样的问题”。这在某些情况下,确实是一种选择。然而当我们使用一个接口或应用时,我们不仅需要通过技术手段(幂等性、熔断等)去提高它们的稳定性,同时也确保因为其他突发原因(如新同事编写的代码导致意外的发生等)带来的问题。

以下几种情况,频率限制可以帮助我们更好的确保API的可用性:

用户使用脚本,向我们发送了大量的请求。

用户向我们发送了许多低优先级接口数据的请求,而我们希望这些低优先级的请求尽量不影响我们高优先级接口请求(如电商,必须保证下单流程是正常的,其他的接口优先级自然低于下单流程相关的接口)。

因突然原因,无法同时正常访问所有接口,因此需要临时丢弃优先级低的请求(当然Nginx层面也是可以实现的)。

令牌桶介绍

令牌桶算法的原理是系统会以一个恒定的速度往桶(bucket)放入令牌(token),而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务(denial of service)。

特点:

当bucket满的时候,将不再放入token,也就是token数量不会超过bucket最大容量。

由于token在一段时间内是有限的,所以即使发生突然流量,也能很好的保护服务。

实现方式

对于令牌桶的实现,一般常用的有两种:

第一种

后台启动一个线程,按照一定的时间颗粒度,不断的往固定大小的桶(bucket)增加令牌(token),直到达到桶的最大容量。

这种做法不仅实现稍微繁琐一点,需要额外维护一个脚本;而且在没有请求的情况下,线程也会不断的去检查更新token,如果key比较多的情况下,对CPU会有较大的性能影响。

第二种(本文案例)

每次访问,将本次访问的时间和速率存入redis,并在下次新的请求访问时,对比当前时间和上次请求时间两个时间差之间的可使用token数量,并将新的结果存入redis。

代码实现

initNum 桶初始大小

expire单位时间

nowTime 当前访问的时间

limitData['time'] 上次请求的时间

namespace app\components;

use yii\base\Component;

class RateLimiter extends Component

{

public $redis = null;

public $cacheKey = null;

// number of visits per minute by a single user

// 单位时间下,单个用户访问的次数

public $initNum = 30;

// unit time

// 单位时间

public $expire = 60;

/**

* RateLimiter constructor.

* @param string $initNum

* @param string $expire

*/

public function __construct($cacheKey = '', $initNum = '', $expire = '')

{

if (empty($cacheKey)) {

return false;

}

$this->redis = \Yii::$app->redis;

$this->initNum = $initNum ?? $this->initNum;

$this->expire = $expire ?? $this->expire;

$this->cacheKey = $cacheKey;

}

/**

* handler

* @return array

*/

public function handler()

{

$ret = self::_limit($this->cacheKey, $this->initNum, $this->expire);

if (empty($ret['status'])) {

return false;

}

return true;

}

private function _limit($cacheKey = '', $initNum = '', $expire = '')

{

$nowTime = time();

$this->redis->watch($cacheKey);

$redisData = $this->redis->get($cacheKey);

$limitData = $redisData ? json_decode($redisData, true) : ['num' => $initNum, 'time' => $nowTime];

// (单位时间访问频率 / 单位时间)*(当前时间 - 上次访问时间) = 上次请求至今可增加的访问次数

$addNum = ($initNum / $expire) * ($nowTime - $limitData['time']);

$newNum = min($initNum, (($limitData['num'] - 1) + $addNum));

if ($newNum <= 0) {

return ['status' => false, 'msg' => '当前时刻令牌用完啦!'];

}

$limitData = json_encode(['num' => $newNum, 'time' => $nowTime]);

$this->redis->multi();

$this->redis->set($cacheKey, $limitData);

if (!$this->redis->exec()) {

return ['status' => false, 'msg' => '访问频次过多!'];

}

return ['status' => true, 'msg' => 'ok'];

}

}

总结

令牌桶频率限制是API接口设计中重要的安全策略之一,但是对于不同的业务和场景都应该使用最适合的方法(如登录密码错误,一天只能尝试五次,这种情况计数器限频就是更好的选择了),万事并无绝对。

参考

https://medium.com/smyte/rate-limiter-df3408325846

https://stripe.com/en-hk/blog/rate-limiters

php令牌桶,令牌桶限频(TokenBucket)相关推荐

  1. PHP+Redis令牌桶算法 接口限流

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

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

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

  3. 如何设计一个速率限制器(令牌桶/漏桶/固定窗口/滑动窗口)

    如何设计一个速率限制器(令牌桶/漏桶/固定窗口/滑动窗口) 在网络系统中,速率限制器被用来控制客户端或服务发送的流量的速率.在 HTTP 领域,速率限制器限制了在指定周期内允许发送的客户端请求的数量. ...

  4. hive 建表,分桶表(clustered by)、分桶且桶内排序(clustered by+sorted by)、分区表(partitioned by)、分区分桶一起用

    一.分桶表 1.建表语句 create table test_bucket_sorted ( id int comment 'ID', name string comment '名字' ) comme ...

  5. 千呼万唤,高并发限流算法之漏桶令牌桶来了!

    等啊等,盼啊盼,11月份终于来了,在11月01日的00:00分,你可以清空掉所有的预售订单,还有购买商家所推出的限时折扣如前十五分钟购买5折等,买的人很开心,商家也很开心.然而程序员们不开心了,提供应 ...

  6. java限频_单个用户及Ip请求频率限制思路(附java实现)

    > 我们熟悉的限流算法漏桶和令牌桶外,很多情况我们还需要考虑当个用户(ip)访问频率控制,避免被恶意调用.如果是开放平台限制一天调用多少次这种粗放的粒度相对好处理一些.如果需要更小时间粒度控制, ...

  7. jwt令牌_JWT令牌的秘密轮换

    jwt令牌 当您使用JSON Web令牌 ( JWT )或需要对有效载荷信息进行签名或加密的任何其他令牌技术时,设置令牌的到期日期很重要,因此,如果令牌到期,则可以假定这可能被视为安全漏洞,您拒绝使用 ...

  8. OAuth2.0_JWT令牌-生成令牌和校验令牌_Spring Security OAuth2.0认证授权---springcloud工作笔记148

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 然后我们在我们的微服务中,开始使用这个JWT令牌,首先 我们原来的授权服务中使用的是自己生成的to ...

  9. 令牌桶算法和漏桶算法有什么区别_高并发之限流,到底限的什么鬼 (精品长文)...

    你可能知道高并发系统需要限流这个东西,但具体是限制的什么,该如何去做,还是模凌两可.我们接下来系统性的给它归个小类,希望对你有所帮助. google guava中提供了一个限流实现: RateLimi ...

  10. 什么是限流?为什么会限流呢?常见的限流算法【固定窗口限流、滑动窗口限流、漏桶限流、令牌桶限流】是什么呢?

    什么是限流?为什么会限流呢?常见的限流算法[固定窗口限流.滑动窗口限流.漏桶限流.令牌桶限流]是什么呢? 什么是限流? 为什么会限流? 1. 固定窗口限流算法 1.1 什么是固定窗口限流算法 1.2 ...

最新文章

  1. 频频霸榜的Python,竟遭开发者嫌弃!
  2. [LeetCode] Palindrome Number Valid Palindrome - 回文系列问题
  3. SpringBoot整合mybatis进行快速开发
  4. c语言中申请内存并初始化,c语言中结构体的定义、初始化及内存分配
  5. 【flink】RocksDB介绍以及Flink对RocksDB的支持
  6. 【Kylin】60-20-040-集成-Kylin集成LDAP
  7. 算法学习--链表/Hash--LRU cache
  8. 阶段5 3.微服务项目【学成在线】_day04 页面静态化_12-页面静态化-页面静态化流程...
  9. 容器技术Docker K8s 19 容器服务ACK基础与进阶-容器网络管理
  10. 阿里巴巴“牛逼”了,申请“行政干预”区块链专利
  11. PC式硬盘录像机常见故障剖析,监控卡常见问题(一)
  12. ❤️1000道《计算机基础知识》汇总上----(建议收藏)❤️
  13. 印刷业ERP系统解决方案
  14. 分享三大外汇日内交易策略
  15. 基于MFC的U盘检测与文件拷贝程序
  16. 分摊的意思_十年分摊是什么意思
  17. 华硕天选3和联想拯救者r9000p哪个好
  18. 理解红黑树及代码实现
  19. 软件的破解原理是什么?
  20. 网站盈利的10种方式

热门文章

  1. 巴特沃斯低通滤波器 matlab,基于MATLAB做巴特沃斯低通滤波器..doc
  2. 我精通Copula、CoVaR、GARCH、ARIMA、协整、VAR、DCC、BEKK、MES、SRISK、最优组合权重、模拟预测等模型
  3. 广和通LTE Cat4模组L716焕新升级,为IoT行业提供经济普适无线应用
  4. DSP ADC模数转换
  5. 蛙人高频交易拆单策略—蛙人高频软件结构及使用说明
  6. 从Multisim入门Altium Designer
  7. 计算机图形学入门:什么是光线追踪?
  8. C语言程序设计基础(02)—— Visual Studio Code 软件安装与使用
  9. 基于SSM的企业人事管理系统(Spring+SpringMVC+Mybatis)
  10. 基于STM32和W5500实现AirPlay音频播放