Rate Limiting em PHP: proteção de API e otimização de carga
\nRate limiting (limitação de velocidade de requisições) é um mecanismo criticamente importante para qualquer aplicação web em PHP, especialmente para APIs públicas. Ele previne abusos, protege contra ataques DDoS, reduz a carga no servidor e garante uma distribuição justa de recursos entre os usuários. Neste artigo, vamos detalhar as bibliotecas e ferramentas populares para implementar rate limiting em PHP.
\n\nAlgoritmos principais de rate limiting
\nAntes de escolher uma biblioteca, é importante entender os algoritmos básicos:
\n- \n
- Token Bucket (Balde de Tokens) — o algoritmo mais flexível. O balde contém N tokens, cada requisição consome um token. Os tokens são reabastecidos a uma taxa definida. \n
- Leaky Bucket (Balde Furado) — as requisições são processadas a uma taxa constante. Requisições excedentes são descartadas ou colocadas em fila. \n
- Fixed Window (Janela Fixa) — as requisições são contadas em um intervalo fixo (ex.: 60 segundos). Simples, mas pode permitir picos de carga nos limites das janelas. \n
- Sliding Window (Janela Deslizante) — um algoritmo mais preciso que considera requisições em uma janela de tempo flutuante. Usa logs ou contadores com carimbos de tempo. \n
Bibliotecas populares para rate limiting em PHP
\n\n1. Symfony Rate Limiter (symfony/rate-limiter)
\nComponente oficial do Symfony, mas também funciona como biblioteca independente. Suporta todos os algoritmos principais: Token Bucket, Fixed Window, Sliding Window. Ideal para projetos em Symfony ou Laravel.
\nuse Symfony\\Component\\RateLimiter\\RateLimiterFactory;\nuse Symfony\\Component\\RateLimiter\\Storage\\InMemoryStorage;\n\n$factory = new RateLimiterFactory([\n 'id' => 'api',\n 'policy' => 'token_bucket',\n 'limit' => 100,\n 'rate' => ['interval' => '1 minute'],\n], new InMemoryStorage());\n\n$limiter = $factory->create('user_123');\n\nif ($limiter->consume(1)->isAccepted()) {\n // Processamento da requisição\n} else {\n // Retorno 429 Too Many Requests\n header('HTTP/1.1 429 Too Many Requests');\n echo json_encode(['error' => 'Rate limit excedido']);\n}\n\n2. nikic/FastRoute com middleware rate limiting
\nSolução leve para projetos sem frameworks. Usa implementação PHP de Token Bucket com armazenamento em Redis ou Memcached.
\nclass RateLimitMiddleware {\n private $redis;\n private $maxRequests = 100;\n private $window = 60; // segundos\n\n public function handle($request, $next) {\n $key = 'rate_limit:' . $_SERVER['REMOTE_ADDR'];\n $current = $this->redis->incr($key);\n \n if ($current === 1) {\n $this->redis->expire($key, $this->window);\n }\n\n if ($current > $this->maxRequests) {\n return new Response('Muitas Requisições', 429);\n }\n\n return $next($request);\n }\n}\n\n3. Laravel Rate Limiter (integrado)
\nNo Laravel, o rate limiting está integrado ao núcleo. Usa Redis ou cache. Suporta limitadores nomeados e segmentação por usuários.
\n// No RouteServiceProvider\nuse Illuminate\\Cache\\RateLimiting\\Limit;\nuse Illuminate\\Http\\Request;\n\nprotected function configureRateLimiting()\n{\n RateLimiter::for('api', function (Request $request) {\n return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());\n });\n}\n\n// No controlador\npublic function index()\n{\n $executed = RateLimiter::attempt(\n 'send-message:'.$user->id,\n $perMinute = 5,\n function() {\n // Envio de mensagem\n }\n );\n \n if (! $executed) {\n return response('Muitas Tentativas.', 429);\n }\n}\n\n4. PHP RateLimit (php-rateLimit/php-rateLimit)
\nBiblioteca universal
Também na biblioteca
Cliente Redis para Go (Golang): go-redis e redigo — guia completo
Testes em Go (Golang): frameworks e ferramentas
Trabalhando com S3 e armazenamentos em nuvem em Rust: biblioteca aws-sdk-s3
Zod para TypeScript: guia completo com exemplos