0

0

Laravel队列如何实现任务的速率限制? (Redis与漏斗算法)

尼克

尼克

发布时间:2026-01-14 23:39:09

|

620人浏览过

|

来源于php中文网

原创

不能。Laravel的throttle方法面向HTTP请求,不适用于队列任务;需用Redis原子操作(如Redis::throttle()或自定义Lua脚本)实现漏斗/令牌桶限流,并配合release()延迟重试。

laravel队列如何实现任务的速率限制? (redis与漏斗算法)

Redis + Laravel 的 throttle 方法能直接限速吗?

不能。Laravel 自带的 throttle 方法(如 RateLimiter::attempt())面向 HTTP 请求,不适用于队列任务调度。队列任务在后台运行,没有请求上下文,直接复用 Web 限流逻辑会失效或误判。

真正可行的方式是:在任务执行前,用 Redis 原子操作模拟漏斗(Leaky Bucket)或令牌桶(Token Bucket),由开发者手动控制「放行」与「延迟重试」。

  • 必须显式调用 Redis::eval()Redis::throttle()(Laravel 9.2+ 提供的封装)
  • 限流粒度需自行定义:按任务类型、用户 ID、租户 ID 等作为 $key 前缀
  • 失败时不能抛异常中断队列,而应调用 $this->release($delay) 延迟重试

Redis::throttle() 实现每秒最多 5 次的任务执行

Laravel 9.2+ 内置了基于 Redis Lua 脚本的漏斗限流封装,底层使用固定窗口 + 计数器,行为接近漏斗但非严格连续漏出。它适合大多数队列节流场景,且无需手写 Lua。

public function handle()
{
    $key = 'job:send_email:'.$this->userId;
$result = Redis::throttle($key)
    ->allow(5)           // 允许每分钟最多 5 次(注意:单位是「每分钟」,不是每秒)
    ->every(60)          // 时间窗口为 60 秒
    ->then(function () {
        // 限流通过,执行业务逻辑
        sendEmail($this->email);
    }, function () {
        // 被限流,延迟 2 秒后重试
        $this->release(2);
    });

}

⚠️ 注意:every(60) 是窗口长度,allow(5) 是该窗口内最大许可数;它不是“每秒 5 次”,而是“60 秒内最多 5 次”。若真要实现每秒级控制,需改用 every(1)->allow(1),但高并发下易被击穿,建议搭配更长窗口 + 合理配额。

自定义漏斗算法:用 Redis::eval() 实现平滑速率控制

当需要严格模拟漏斗(如“每 200ms 放行 1 个任务”),必须手写 Lua 脚本。核心思路是:记录上一次通过时间,计算当前是否已“漏出”足够令牌。

以下脚本实现「固定间隔漏出」:每 $intervalMs 毫秒允许 1 次,自动累积最多 $capacity 个令牌:

Interior AI
Interior AI

AI室内设计,上传室内照片自动帮你生成多种风格的室内设计图

下载
Redis::eval("
    local key = KEYS[1]
    local interval_ms = tonumber(ARGV[1])
    local capacity = tonumber(ARGV[2])
    local now = tonumber(ARGV[3])
local last_time, tokens = unpack(redis.call('hmget', key, 'last_time', 'tokens'))
last_time = tonumber(last_time) or 0
tokens = tonumber(tokens) or capacity

-- 计算应新增令牌数(按时间推移)
local elapsed = now - last_time
local new_tokens = math.min(capacity, tokens + elapsed / interval_ms)

if new_tokens >= 1 then
    redis.call('hset', key, 'last_time', now)
    redis.call('hset', key, 'tokens', new_tokens - 1)
    return 1
else
    redis.call('hset', key, 'last_time', last_time)
    redis.call('hset', key, 'tokens', new_tokens)
    return 0
end

", 1, 'leaky:send_sms:'.$this->phone, 200, 5, round(microtime(true) * 1000));

返回 1 表示可执行,0 表示需等待。你需据此决定是否 release() 并设置合理延迟(例如再等 200 - (now - last_time) ms)。

为什么不能只靠 delay() 或数据库字段控制速率?

单纯在任务分发时用 dispatch()->delay(30) 只能控制「首次延后」,无法应对持续高频入队;而依赖数据库时间戳做查询判断(如 where('last_run_at', 'subSeconds(2)))存在竞态条件——多个 worker 同时读到“可执行”,然后一起写入,导致超发。

根本原因在于:限速是分布式状态协调问题,必须依赖原子性存储(Redis)和原子操作(evalthrottle 封装)。任何非原子的“读-判-写”流程,在多 worker 场景下都不可靠。

漏斗逻辑本身不难,难的是把时间精度、令牌累积、错误重试、监控埋点这几件事串成一条不丢、不重、可观测的链路——实际落地时,80% 的坑出在延迟重试的指数退避没做,或者限流 key 没带上业务维度,导致全站共用一个桶。

相关专题

更多
laravel组件介绍
laravel组件介绍

laravel 提供了丰富的组件,包括身份验证、模板引擎、缓存、命令行工具、数据库交互、对象关系映射器、事件处理、文件操作、电子邮件发送、队列管理和数据验证。想了解更多laravel的相关内容,可以阅读本专题下面的文章。

316

2024.04.09

laravel中间件介绍
laravel中间件介绍

laravel 中间件分为五种类型:全局、路由、组、终止和自定。想了解更多laravel中间件的相关内容,可以阅读本专题下面的文章。

271

2024.04.09

laravel使用的设计模式有哪些
laravel使用的设计模式有哪些

laravel使用的设计模式有:1、单例模式;2、工厂方法模式;3、建造者模式;4、适配器模式;5、装饰器模式;6、策略模式;7、观察者模式。想了解更多laravel的相关内容,可以阅读本专题下面的文章。

369

2024.04.09

thinkphp和laravel哪个简单
thinkphp和laravel哪个简单

对于初学者来说,laravel 的入门门槛较低,更易上手,原因包括:1. 更简单的安装和配置;2. 丰富的文档和社区支持;3. 简洁易懂的语法和 api;4. 平缓的学习曲线。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

370

2024.04.10

laravel入门教程
laravel入门教程

本专题整合了laravel入门教程,想了解更多详细内容,请阅读专题下面的文章。

81

2025.08.05

laravel实战教程
laravel实战教程

本专题整合了laravel实战教程,阅读专题下面的文章了解更多详细内容。

64

2025.08.05

laravel面试题
laravel面试题

本专题整合了laravel面试题相关内容,阅读专题下面的文章了解更多详细内容。

67

2025.08.05

登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

6084

2023.09.14

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

36

2026.01.14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Laravel---API接口
Laravel---API接口

共7课时 | 0.6万人学习

PHP自制框架
PHP自制框架

共8课时 | 0.6万人学习

PHP面向对象基础课程(更新中)
PHP面向对象基础课程(更新中)

共12课时 | 0.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号