分享个自己封装的限流trait

<?php namespace App\Traits; use App\Exceptions\BusinessException; use Illuminate\Support\Facades\Redis; trait RedisLimiter { /** * 限流 * @param $key * @param $limit * @param $expire_time * @return bool * @throws BusinessException * @author wzx 2023/4/25 17:35 */ public static function set($key, $limit, $expire_time) { $current_time = time(); $result = Redis::eval(self::lua(), 1, $key, $limit, $expire_time, $current_time); if ($result == 0) { throw new BusinessException([-1, '请求频繁']); } return true; } private static function lua(): string { return <<<LUA local key = KEYS[1] local limit = tonumber(ARGV[1]) local expire_time = tonumber(ARGV[2]) local current_time = tonumber(ARGV[3]) local count = redis.call('get', key) if count and tonumber(count) >= limit then return 0 else redis.call('incr', key) redis.call('expire', key, expire_time) return 1 end LUA; } } 

使用

$key = "user:xxx" . $user_id; // 一分钟请求1次 RedisLimiter::set($key, 1, 60);
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 11

不错,laravel已经内置了

use Illuminate\Support\Facades\Redis; Redis::funnel(self::JOBS_PREFIX . $this->domain) ->limit(1) ->then(fn() => $this->executor());
2年前 评论

不错,laravel已经内置了

use Illuminate\Support\Facades\Redis; Redis::funnel(self::JOBS_PREFIX . $this->domain) ->limit(1) ->then(fn() => $this->executor());
2年前 评论

这是固定时间窗口吧?

2年前 评论

没玩过Lua,用redis调Lua再调redis ,跟直接用redis有什么区别。

2年前 评论
panda-sir 2年前
kkokk 2年前
白小二 2年前

不是原生就有 ThrottleRequestsWithRedis

2年前 评论

Illuminate\Redis\Limiters\DurationLimiter

2年前 评论

没怎么用过,跟原生的有哪些不一样

2年前 评论

疑问:

  1. current_time 有什么用?看代码貌似没用上
  2. 每次更新 expire 的时间合理吗?
2年前 评论

在应用层限流有瓶颈,流量上来,会直接把服务打挂了,建议在网关层限流,推荐 apisix。

2年前 评论