本文目录导读:

在 Laravel 中,官方限流器 Illuminate\Cache\RateLimiter 底层使用的是令牌桶算法。
具体原因和对比分析如下:
- Laravel 内置限流器 → 令牌桶算法
- Nginx 限流 → 漏桶算法(
limit_req模块) - Redis + Lua 自定义 → 两种均可实现
为什么 Laravel 选择令牌桶?
令牌桶算法核心特性
- 允许突发流量 (Burst):只要桶内有足够令牌,可以瞬间处理大量请求。
- 平滑限流:令牌以固定速率补充,长期平均速率可控。
Laravel 的 RateLimiter 行为验证(代码逻辑):
// 以“每分钟 10 次”为例
RateLimiter::for('api', function ($job) {
return Limit::perMinute(10);
});
- 前 59 秒未请求:桶内积攒 10 个令牌。
- 第 60 秒瞬间请求 10 次:全部放行(突发)。
- 第 61 秒再次请求:被拒绝(桶已空,令牌未补充)。
这正是令牌桶的典型表现 —— 允许短时间内的突发流量。
漏桶算法的典型表现
- 严格平滑:即使瞬间请求 100 次,也只以固定速率(如 10转/分钟)向外放行,多余的请求直接丢弃或排队。
- 无法利用空闲时间:漏桶的“积水”恒定速度流出,不会因为之前空闲而允许更大的突发。
对比示例(同一场景):
| 时间点 | 请求数 | 令牌桶(Laravel) | 漏桶 |
|---|---|---|---|
| T=0 | 100 | 放行 10 次,拒绝 90 次 | 放行 10 次,拒绝 90 次 |
| T=60(空闲 59 秒) | 100 | 放行 100 次(桶积攒了 100 令牌) | 放行 10 次,拒绝 90 次 |
Laravel 选择令牌桶就是因为 Web 应用需要容忍突发流量(如用户刷新、秒杀开始瞬间)。
如何确认 Laravel 的实现?
可以直接查看 Laravel 源码中 Illuminate\Cache\RateLimiter 的 hit 方法:
public function hit($key, $decaySeconds = 60)
{
$this->cache->add($key, 0, $decaySeconds);
$this->cache->increment($key);
// ... 还有 attempts() 方法读取当前次数
}
- 它基于 Redis + 计数器实现。
- 没有基于时间戳的严格“流出速率”控制,而是通过 固定时间窗口 + 计数重置(
decaySeconds)来模拟令牌的“补充”。 - 这种实现本质上是一种 区间令牌桶(Fixed Window + Burst Allowed)。
什么时候需要考虑换成漏桶?
| 场景 | 推荐算法 |
|---|---|
| API 网关、视频流、下载服务(要求绝对平滑,防止突刺) | 漏桶 |
| 用户操作接口(如发帖、登录)(允许短暂突发,符合人类行为) | 令牌桶(Laravel 默认) |
| 秒杀系统、抢红包(需要精确控制瞬间流量,平滑流出) | 漏桶 + 队列排队 |
在 Laravel 中实现漏桶(如果需要)
Laravel 没有内置漏桶,但可以借助 Redis + Lua 实现:
-- 漏桶 Lua 脚本
local key = KEYS[1]
local leak_rate = tonumber(ARGV[1]) -- 漏水速率 (请求/秒)
local capacity = tonumber(ARGV[2]) -- 桶容量
local now = tonumber(ARGV[3])
local water = redis.call('get', key)
if water == false then
water = 0
redis.call('set', key, 0)
end
-- 先漏水(根据时间差)
local leak_amount = (now - tonumber(redis.call('ttl', key))) * leak_rate
water = math.max(0, water - leak_amount)
if water < capacity then
redis.call('set', key, water + 1)
return 1 -- 放行
else
return 0 -- 拒绝
end
但这样会丧失 Laravel 内置的优雅语法和 Redis 原子递增优势。
| 令牌桶(Laravel 默认) | 漏桶 | |
|---|---|---|
| 突发容忍 | ✅ 允许 | ❌ 严格平滑 |
| 实现复杂度 | 低(内置) | 高(需自写 Lua) |
| 适用场景 | 通用 Web API、用户操作 | 严格限流、流量整形 |
| 是否推荐 | ✅ 默认首选 | ❌ 除非有明确平滑需求 |
建议: 在 99% 的 Laravel 项目中,直接使用内置的 RateLimiter(令牌桶)即可,只有当你的业务逻辑明确要求“平滑输出”(如视频帧推流、实时数据管道)时,才考虑通过 Redis+Lua 或 Nginx 实现漏桶。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播