分享个自己封装的限流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 协议》,转载必须注明作者和本文链接
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 11

不错,laravel已经内置了

use Illuminate\Support\Facades\Redis;

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

不错,laravel已经内置了

use Illuminate\Support\Facades\Redis;

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

这是固定时间窗口吧?

1年前 评论

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

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

不是原生就有 ThrottleRequestsWithRedis

1年前 评论

Illuminate\Redis\Limiters\DurationLimiter

1年前 评论

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

1年前 评论

疑问:

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

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

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!