Crater API限流实现:使用Redis与Lua脚本

Crater API限流实现:使用Redis与Lua脚本

【免费下载链接】crater Open Source Invoicing Solution for Individuals & Businesses 【免费下载链接】crater 项目地址: https://gitcode.com/gh_mirrors/cr/crater

限流方案概述

Crater作为开源发票管理系统,API接口需要保护机制防止滥用。基于Redis的令牌桶算法是实现限流的高效方案,通过Lua脚本保证原子性操作,支持分布式环境下的精确限流控制。

核心实现文件

系统限流功能主要通过以下文件实现:

Redis配置详解

config/database.php中配置Redis连接信息:

'redis' => [
    'client' => env('REDIS_CLIENT', 'predis'),
    'options' => [
        'cluster' => env('REDIS_CLUSTER', 'redis'),
        'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
    ],
    'default' => [
        'url' => env('REDIS_URL'),
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD'),
        'port' => env('REDIS_PORT', '6379'),
        'database' => env('REDIS_DB', '0'),
    ],
],

Lua限流脚本

限流逻辑通过Lua脚本实现原子性操作,脚本存储在app/Services/Redis/RateLimitScript.php:

local key = KEYS[1]
local capacity = tonumber(ARGV[1])
local rate = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local requested = tonumber(ARGV[4])

local fill_time = capacity / rate
local ttl = math.floor(fill_time * 2)

local last_tokens = tonumber(redis.call("get", key..":tokens")) or capacity
local last_refreshed = tonumber(redis.call("get", key..":refreshed")) or 0

local delta = math.max(0, now - last_refreshed)
local filled_tokens = math.min(capacity, last_tokens + (delta * rate))
local allowed = filled_tokens >= requested
local new_tokens = filled_tokens
local allowed_num = 0

if allowed then
    new_tokens = filled_tokens - requested
    allowed_num = 1
end

redis.call("setex", key..":tokens", ttl, new_tokens)
redis.call("setex", key..":refreshed", ttl, now)

return {allowed_num, new_tokens}

限流中间件实现

app/Http/Middleware/RateLimitMiddleware.php实现请求拦截与限流判断:

public function handle($request, Closure $next)
{
    $redis = Redis::connection();
    $key = 'ratelimit:'. $request->ip();
    $capacity = config('crater.rate_limit.capacity', 60);
    $rate = config('crater.rate_limit.rate', 1);
    $now = microtime(true);
    $requested = 1;

    $script = $this->getRateLimitScript();
    $result = $redis->eval($script, 1, $key, $capacity, $rate, $now, $requested);

    if ($result[0] == 0) {
        return response()->json([
            'error' => 'Rate limit exceeded',
            'retry_after' => (int)ceil($capacity / $rate)
        ], 429);
    }

    return $next($request)
        ->header('X-RateLimit-Limit', $capacity)
        ->header('X-RateLimit-Remaining', $result[1]);
}

应用限流策略

routes/api.php中为需要保护的路由添加限流中间件:

Route::middleware(['auth:sanctum', 'ratelimit'])->group(function () {
    Route::apiResource('invoices', InvoiceController::class);
    Route::apiResource('estimates', EstimateController::class);
    Route::apiResource('customers', CustomerController::class);
});

配置参数说明

限流参数可通过config/crater.php进行调整:

'rate_limit' => [
    'enabled' => env('RATE_LIMIT_ENABLED', true),
    'capacity' => env('RATE_LIMIT_CAPACITY', 60), // 最大令牌数
    'rate' => env('RATE_LIMIT_RATE', 1), // 每秒生成令牌数
],

监控与扩展

系统提供限流监控接口,通过app/Http/Controllers/Api/RateLimitController.php暴露当前限流状态,可结合Prometheus等工具实现可视化监控。对于高并发场景,可通过调整Redis集群配置和限流参数实现弹性扩展。

实现流程图

mermaid

性能优化建议

  1. 使用Redis Pipeline减少网络往返
  2. 合理设置TTL避免键值堆积
  3. 针对不同API设置差异化限流策略
  4. 实现动态限流参数调整机制
  5. 考虑地理分布式限流方案

【免费下载链接】crater Open Source Invoicing Solution for Individuals & Businesses 【免费下载链接】crater 项目地址: https://gitcode.com/gh_mirrors/cr/crater

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值