【问题标题】:Laravel queue rate limiting or throttlingLaravel 队列速率限制或节流
【发布时间】:2018-05-04 02:54:20
【问题描述】:

我正在开发一个需要从第三方服务器获取数据并且该服务器每秒最多允许 1 个请求的应用程序。

现在,所有请求都作为作业发送,我正在尝试实施 Laravel "Rate Limiting" 以每秒释放 1 个作业,但无法弄清楚为什么应该实施它,并且网络中没有现实生活中的示例。

有人实现了吗?

有什么提示吗?

【问题讨论】:

  • 自己调用内部API来消费外部API,使用job来消费自己的内部API。速率限制您自己的内部 API。
  • 我现在正在做类似的事情,我的想法是:当您将作业分派到队列时,将分派日期时间存储在缓存中。对于所有调度,检查缓存以查看最后一个作业的调度时间,如果小于 1 秒,则使用 Job::dispatch()->delay($lastDispatchDateTime->addSeconds(1));

标签: laravel laravel-5 queue laravel-queue


【解决方案1】:

spatie/laravel-rate-limited-job-middleware

如果您使用的是 laravel 6 或更高版本,这是一个不错的软件包。好在你可以在作业中配置中间件。

安装

composer require spatie/laravel-rate-limited-job-middleware

【讨论】:

    【解决方案2】:

    我是mxl/laravel-queue-rate-limit Composer 包的作者。

    它允许您在不使用 Redis 的情况下对特定队列上的作业进行速率限制。

    1. 安装它:

      $ composer require mxl/laravel-queue-rate-limit:^1.0
      
    2. 此包兼容 Laravel 5.5+,并使用auto-discovery 功能将MichaelLedin\LaravelQueueRateLimit\QueueServiceProvider::class 添加到提供程序。

    3. config/queue.php添加速率限制设置:

      'rateLimit' => [
          'mail' => [
              'allows' => 1,
              'every' => 5
          ]
      ]
      

      这些设置允许在 mail 队列上每 5 秒运行 1 个作业。 确保默认队列驱动程序(config/queue.php 中的default 属性)设置为除sync 之外的任何值。

    4. 使用--queue mail 选项运行队列工作者:

      $ php artisan queue:work --queue mail
      

      您可以在多个队列上运行工作器,但只有 rateLimit 设置中引用的队列会受到速率限制:

      $ php artisan qeueu:work --queue mail,default
      

      default 队列上的作业将在没有速率限制的情况下执行。

    5. 排队一些作业以测试速率限制:

      SomeJob::dispatch()->onQueue('mail');
      SomeJob::dispatch()->onQueue('mail');
      SomeJob::dispatch()->onQueue('mail');
      SomeJob::dispatch();
      

    【讨论】:

      【解决方案3】:

      如果您需要“节流”并且不使用 Redis 作为队列驱动程序,您可以尝试使用以下代码:

      public function throttledJobDispatch( $delayInSeconds = 1 ) 
      {
         $lastJobDispatched = Cache::get('lastJobDispatched');
      
         if( !$lastJobDispatched ) {
            $delay_until = now();
         } else { 
            if ($lastJobDispatched->addSeconds($delayInSeconds) < now()) {
               $delay_until = now();
            } else {
               $delay_until = $lastJobDispatched->addSeconds($delayInSeconds);
            }
         }
         Job::dispatch()->onQueue('YourQueue')->delay($delay_until);
         Cache::put('lastJobDispatched', $delay_until, now()->addYears(1) );
      }
      

      此代码的作用是将作业释放到队列中,并在最后一个分派作业的开始时间之后设置开始时间 X 秒。我成功地使用数据库作为队列驱动程序和文件作为缓存驱动程序进行了测试。

      目前我遇到了两个小问题:

      1) 当您仅使用 1 秒作为延迟时,具体取决于您的队列工作人员 - 队列工作人员实际上可能每隔几秒“唤醒”一次。因此,如果它每 3 秒唤醒一次,它将一次执行 3 个作业,然后再次“休眠”3 秒。但平均而言您仍然每秒只会执行一项工作。

      2) 在 Laravel 5.7 中,无法使用 Carbon 将作业延迟设置为小于一秒,因为它还不支持毫秒或微秒。 Laravel 5.8 应该可以做到这一点 - 只需使用 addMilliseconds 而不是 addSeconds

      【讨论】:

        【解决方案4】:

        您可以使用此包对 Redis 或其他源(如文件)使用速率限制。使用设置将存储桶大小和速率设置为时间限制的分数,因此存储空间非常小。

        composer require bandwidth-throttle/token-bucket
        

        https://github.com/bandwidth-throttle/token-bucket

        它允许您将检查包装在 if 中,因此它将等待免费令牌可用,在您的示例中每分钟 1 个。实际上,它使服务休眠所需的时间,直到新的一分钟。

        【讨论】:

          【解决方案5】:

          假设你只有一个工人,你可以这样做:

          • 做该做的事
          • 获取时间(以微秒计)
          • 睡眠时间是 1 秒减去结束时间和开始时间之间的差值

          基本上就是这样:

          doSomething()
          $time = microtime(true);
          usleep(1000 - ($time - LARAVEL_START));
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-08-02
            • 2019-12-25
            • 2015-03-19
            • 1970-01-01
            相关资源
            最近更新 更多