美文网首页
网站限流的实现

网站限流的实现

作者: 云龙789 | 来源:发表于2020-09-07 15:28 被阅读0次
  • 场景

比如要实现在1S内,ip是127.0.0.1 的用户对api/test 接口的请求不能超过 1000 次

  • 实现思路

在 redis 队列中,对于同一个 ip,永远保持有1000个以毫秒为值的队列,每次请求,取出队列的第一个值,并重新生成一个新的时间值,放在队列的末尾。比较这两个时间,如果间隔超过1S,则表示请求频率超过了设定频率

  • 实现步骤

生成1000个令牌,放入127.0.0.1 的 redis 队列。保持队列中永远有1000个令牌。当有请求过来时,拿掉队列中第一个令牌(比如值是1.1111),并且重新生成一个新的令牌(比如值是1.9999),放在队列的最后一位。
1.9999-1.1111 这个时间在1S内,则表示可以继续请求,如果这个值超过1S,则表示请求频率超出了设定频率

photo_2020-09-07_14-44-16.jpg

我们使用 php 的 microtime(true) 系统函数,获取当前时间戳和微秒数
1秒=1000000 微秒(μs), 1微秒=1/1000000秒(s);
所以,我们直接使用 microtime(true)*1000 来作为我们的队列值即可

$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);

$key=\Request::ip(); // 请求的ip   如果我们是对所有请求者做的统一频率限制,则使用固定 key 即可
$redis_len = $redis->lLen($key); //  队列的长度 
if ($redis_len <1000){
// 如果长度不够1000 则补齐1000条数据。但理论上是只有第一次数据不够,或者说某个ip好久没有请求,超过了redis key 的设定过期时间。否则key是永远能保持一千条数据的
  for ($i=1;$i<=1000-$redis_len){
    $redis->rPush($key,microtime(true)*1000);
  }
}
//  获取队列的第一个时间
$first_time = $redis->lPop($key); // 从左侧获取第一个值
$now = microtime(true)*1000; // 现在的时间

if(($now-$first_time)>1000){
// 不符合需求,我们还将原来的值放回队列
  $redis->lPush($key, $first_time ); // 刚才是从左侧弹出的,我们再从左侧放入,还保证他是第一个值
// 也可以在上面直接获取第一个值,而不是弹出,这样的话,就不用再重新放入这个值了
  die('请求频率超过了设定的每秒1000条数据');
  }else{
//可以处理本次请求
    $redis->rPush($key, $now); // 将现在的时间放入队列
  }

-注意
设置频率限制可能有两种方案

一种是,超过频率设定的请求,不做正常的请求处理,如果你一直是每秒1000以上的频率,比如你每秒1500条请求,则程序会在后500条不做处理,之后的请求,已经到了放开频率现在的时间了,会重新处理。上面的代码是按照这种方案处理的

另一种是,超过频率设定的请求,也算是一次请求。这种情况下,如果你一直是每秒1000以上的频率,则你会一直请求失败
不管是否可以请求。正常的队列 lPop 和 rPush 都是要继续的,因为,即使是超过了频率,客户可能还是会以这种频率请求,我们仍然要制止

$start = intval(microtime(true) * 1000);
dump($start); // 1599463467616
usleep(1000 * 100);
$end = intval(microtime(true) * 1000);
dump($end); // 1599463467719
dd($end-$start); // 103
  • 注意

程序运行也需要时间,这个时间查是多少,则需要你自己去判断处理的。但是我们的 start 和 end 代码位置很近,理论上不会有太大的时间差。所以这个也可以忽略

相关文章

  • 网站限流的实现

    场景 比如要实现在1S内,ip是127.0.0.1 的用户对api/test 接口的请求不能超过 1000 次 实...

  • Redis哨兵模式实现网站限流

    一、Redis介绍 Redis是一个开源的使用C语言编写,支持网络,可基于内存亦可持久化的日志型、key-val...

  • PHP中接口限流实现

    代码中实现单个用户限流,uid换为接口名,即可实现接口限流

  • 【NGINX入门】16.使用JMeter压力测试工具测试NGIN

    1. 摘要 本文介绍WINDOWS环境下,使用压力测试工具JMeter实现对网站的NGINX限流配置后,进行压力测...

  • 限流降级方案

    限流算法 并发数限流 计数器并发数限流:使用共享变量实现 信号量:使用java中的Semaphore QPS限流 ...

  • Semaphore CountDownLatch CyclicB

    限流可分为并发限流和速率限流。 Semaphore就属于并发限流的实现。 插句话:速率限流一般限的是QPS,即一秒...

  • 谷歌Guava限流工具RateLimiter

    基于guava-29.0版本。 RateLimiter是一个基于令牌桶算法实现的限流器,常用于控制网站的QPS。与...

  • 大型网站限流算法的实现和改造

    最近写了一个限流的插件,所以避免不了的接触到了一些限流算法。本篇文章就来分析一下这几种常见的限流算法 分析之前 依...

  • 聊聊高并发系统之限流特技-2

    摘要:上一篇《聊聊高并发系统限流特技-1》讲了限流算法、应用级限流、分布式限流;本篇将介绍接入层限流实现。 接入层...

  • RateLimiter-源码分析

    一、前言 在分布式系统中,实现高可用有三大利器: 限流 降级 熔断我们先对限流来进行一个分析。 二、限流的实现 业...

网友评论

      本文标题:网站限流的实现

      本文链接:https://www.haomeiwen.com/subject/ostlektx.html