avatar

麦兜的小站

MDO.INK

  • 首页
  • 随笔
  • 知识库
  • 归档
  • 动态
  • 标签
  • 关于
Home PHP 接口限流实现方法
文章

PHP 接口限流实现方法

Posted 2025-02-10 Updated 2025-02- 10
By power 已删除用户
14~18 min read

因为现在动不动就说高并发,说到高并发 就不得不提并发下限流、熔断、降级。
为什么要进行接口限流呢?
个人认为其实目的都是为了保证线上系统的稳定性,防止因为高频访问服务器而导致服务器宕机。

下面来简单实现一下接口限流的常用算法

这应该是最简单也是最容易实现的,比如A接口1分钟内的访问次数不能超过100个。那么可以这么做:在一开始的时候,设置一个计数器counter,每当一个请求过来的时候,counter就加1,如果counter的值大于100并且该请求与第一个请求的间隔时间还在1分钟之内,那么说明请求数过多;如果该请求与第一个请求的间隔时间大于1分钟,就重置计数器。为了保证高并发下的原子性使用redis的incr实现计数器限流。

public function __construct()
{
   $this->redis = new Redis();
   $this->redis->connect('127.0.0.1', 6379);
}

   public function getApi()
   {





       $res = $this->leakBucket();
       $data = [
           'msg' => '获取成功',
           'code' => 200
       ];

       if (!$res) {
           $data['msg'] = '请稍后重试';
           $data['code'] = 400;
       }
       return $data;
   }
 * @Notes: redis 使用计数器进行限流
 * @Author:如果,
 * @Date: 2022/9/16,
 * @Time: 20:05,
 * @return bool
 */
public function SpeedCounter()
{
    $redis = $this->redis;

    $limitTime = 60;

    $maxCount = 10;
    $redisKey = "userRequestNum";

    $count = $redis->incr($redisKey);
    print_r($count);

    echo PHP_EOL;
    if ($count == 1) {
        $redis->expire($redisKey, $limitTime);
    }

    if ($count > $maxCount) {
        return false;
    }

    return true;
}
 * @Notes: redis 使用计数器进行限流
 * @Author:如果,
 * @Date: 2022/9/16,
 * @Time: 20:05,
 * @return bool
 */
public function SpeedCounter()
{
    $redis = $this->redis;

    $limitTime = 60;

    $maxCount = 10;
    $redisKey = "userRequestNum";

    $count = $redis->incr($redisKey);
    print_r($count);

    echo PHP_EOL;
    if ($count == 1) {
        $redis->expire($redisKey, $limitTime);
    }

    if ($count > $maxCount) {
        return false;
    }

    return true;
}

手动执行php文件 前面10次都可以访问后面10次我们主动拦截请求 粗略的看是实行了限流的方法。这方法存在的问题就是最后1秒内涌入所有请求,然后计数器过期重置后第一秒内又涌入大量请求 这样服务器还是可能会被高频访问搞挂。为了解决这种方法又出现了滑动窗口算法

百度拿的图,滑动窗口个人认为其实就是多存了时间,每次请求进来后时间范围之外的数据将被动态删除。主要使用redis的zset结构来实现

 * @Notes:滑动窗口算法
 * @Author:如果,
 * @Date: 2022/9/16,
 * @Time: 20:20,
 */
public function SlideTimeWindow()
{

     * 2.redis 滑动窗口实现方式
     * 限制1分钟内最大只能请求10次
     * 使用redis事务保证redis原子性
     */
    $redis = $this->redis;
    $limitTime = 60;
    $maxCount = 10;
    $redisKey = "slide_api";
    $nowTime = time();


    $pipe = $redis->multi();


    $pipe->zAdd($redisKey, $nowTime, $nowTime);


    $pipe->zRemRangeByScore($redisKey, 0, $nowTime - $limitTime);

    $pipe->zCard($redisKey);

    $pipe->expire($redisKey, 60 + 1);

    $replies = $pipe->exec();


    return $replies[2] <= $maxCount;
}

主要就是根据时间判断总体思路和计数器差不多
然后来执行一下查看效果

可以看到10次之后就拦截了请求。

顾名思义漏斗,其实就是处理的速度是一定的。主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。漏斗算法提供了一种机制,通过它,突发流量可以被整形以便为网络提供一个稳定的流量。但是多余的请求将会被直接丢弃。 我更觉得是将流量控制在自己可以承受范围内,自己控制流量的速度。 处理请求的worker以固定的速度从桶中取出请求进行处理。 如果桶满了,直接返回请求频率超限的错误码或者页面 限流 体现在worker从桶中取请求的速度上

流量最均衡的限流实现方式。nginx的limit模块就是使用了漏斗算法

private $_water;    
private $_burst = 10;   
private $_rate = 1; 
private $_lastTime; 


 * @Notes:漏斗算法
 * @Author:如果,
 * @Date: 2022/9/16,
 * @Time: 21:03,
 */
public function leakBucket()
{

    $nowTime = time();
    $redisKey = "leakBucket_api";

    if (!empty($time = $this->redis->get($redisKey))) {
        $this->_lastTime = $time; 
    }

    if (!empty($water = $this->redis->get('water'))) {
        $this->_water = $water;
    }

    $s = $nowTime - $this->_lastTime; 

    $outCount = $s * $this->_rate;


    $this->_water = ($this->_water - $outCount);

    if ($this->_water <= 0) {
        $this->_water = 0; 
    }

    if ($this->_water > $this->_burst) {
        echo "超出桶限制" . PHP_EOL;
        return false;
    }

    print_r($this->_water);

    $this->redis->set($redisKey, $nowTime);

    $this->redis->set('water', $this->_water + 1);
}

不足之处在于:
面对突发流量时会有大量请求失败,但是我们可以使用预先准备好的资源返回。

知识库
License:  CC BY 4.0
Share

Further Reading

Jul 31, 2025

如何实现接口幂等性

通俗的说,用户在系统中有操作,不管重复多少次,都应该产生一样的效果或返回一样的结果的。 幂等性的概念 幂等(Idempotent)是一个数学与计算机学的概念,常见于抽象代数中。 f(n)=1^n//无...

Jul 19, 2025

10个npm工具包

有了npm之后,前端人员真的是过上好日子了。我们可以直接把别人写好的工具包拿来用,非常的方便。 1.day.js-轻量日期处理 npminstalldayjs importdayjsfrom'd...

Jul 17, 2025

How to set up PHP7.4 on MacOS.

Thisisallverywellandgood.Apartfromonesmallinsignificantthing… TheversionofPHPinuseiscurrently7.4. Th...

OLDER

Git Commit 规范

NEWER

vue3中当路由一样,参数quary不一样的跳转

Recently Updated

  • 如何实现接口幂等性
  • 10个npm工具包
  • How to set up PHP7.4 on MacOS.
  • Automa:一键自动化,网页数据采集与工作流程优化专家Automa:解锁自动化
  • Mac 下用 brew 搭建 LNMP

Trending Tags

thinkphp clippings

Contents

©2025 麦兜的小站. Some rights reserved.

Using the Halo theme Chirpy