Saltar para o conteúdo
Blume
Esc
↑↓navegar↵abrir⌘Jpré-visualizar
Nesta página

Limite de requisições

Limite com que frequência um mesmo leitor pode chamar o assistente, o proxy do playground da API e a busca no servidor. Vem ativado por padrão, com a contagem mantida em memória, no Upstash, no Cloudflare ou no Unkey.

Cada chamada às rotas de servidor que um leitor pode acessar tem um custo para você: o assistente gasta tokens do modelo, o proxy do playground da API repassa requisições para a sua API e a busca do Mixedbread faz uma consulta paga. O Blume limita com que frequência um mesmo leitor, identificado pelo endereço IP, pode chamar cada uma dessas rotas. Quem passa do limite recebe 429 Too Many Requests com um cabeçalho Retry-After, e o assistente avisa para tentar de novo em alguns minutos.

O limite de requisições vem ativado por padrão, com 30 requisições por leitor por rota a cada 10 minutos. É bem mais do que uma pessoa envia ao assistente ou ao playground, e pouco o bastante para barrar um script. A busca conta de outro jeito. A janela de busca envia uma consulta toda vez que o leitor faz uma pausa enquanto digita, então uma única busca pode gerar várias requisições, e um leitor que busca sem parar por alguns minutos pode chegar ao limite. Se o seu site usa a busca do Mixedbread, aumente requests, que vale para todas as rotas. O limite de requisições só faz diferença em um build com servidor, já que um site estático não tem rotas de servidor para limitar.

import { defineConfig } from "blume";
import { upstash } from "blume/ratelimit";

export default defineConfig({
  rateLimit: upstash({ requests: 30, window: 600 }), // window in seconds
});

Cada rota tem sua própria contagem, então uma sessão intensa no playground não gasta as perguntas que o leitor ainda pode fazer ao assistente.

Onde a contagem fica

Adaptador Contagem mantida em Como o limite é aplicado
memory() Na memória do servidor (o padrão) Com exatidão em um único servidor; por instância em hosts serverless
upstash() Upstash Redis Com exatidão, em qualquer host
cloudflare() No rate limiting do Cloudflare Workers Por localização do Cloudflare
unkey() Unkey Em qualquer host; as regiões se sincronizam em instantes

Memória

memory() não precisa de nenhuma configuração. Em um servidor que roda como um único processo, como deployment: node(), a contagem é exata. Vercel, Netlify e Cloudflare rodam várias instâncias de vida curta, cada uma com sua própria contagem. Nesses hosts, ele barra uma rajada de requisições de um mesmo leitor, mas não aplica o limite com exatidão. Para ter um limite exato nesses hosts, use um dos armazenamentos compartilhados abaixo.

import { memory } from "blume/ratelimit";

rateLimit: memory({ requests: 60, window: 600 }),

Upstash

upstash() guarda a contagem no Upstash Redis, compartilhado por todas as instâncias. Crie um banco de dados e defina o endpoint REST e o token dele como UPSTASH_REDIS_REST_URL e UPSTASH_REDIS_REST_TOKEN. O Blume se comunica com a API REST do Upstash, então você não precisa instalar nada. Enquanto as duas variáveis não estiverem definidas, as rotas contam em memória e o blume build mostra um aviso.

import { upstash } from "blume/ratelimit";

rateLimit: upstash(),

Já um banco de dados adicionado pelo Marketplace da Vercel define o endpoint e o token como KV_REST_API_URL e KV_REST_API_TOKEN, com o prefixo que você tiver escolhido ao conectá-lo. Indique os nomes das variáveis com urlEnv e tokenEnv:

rateLimit: upstash({ urlEnv: "KV_REST_API_URL", tokenEnv: "KV_REST_API_TOKEN" }),

Cloudflare

cloudflare() faz a contagem com o rate limiting do Workers, para sites publicados com deployment: cloudflare(). O Blume declara o binding na configuração do Worker durante o build, então você não precisa configurar nada. O Cloudflare conta por localização e só aceita janelas de 10 ou 60 segundos. Por isso, os padrões dele são 10 requisições a cada 60 segundos.

import { cloudflare } from "blume/deploy";
import { cloudflare as cloudflareRateLimit } from "blume/ratelimit";

export default defineConfig({
  deployment: cloudflare(),
  rateLimit: cloudflareRateLimit({ requests: 10, window: 60 }),
});

O namespace do binding é definido a partir do nome do Worker, então dois sites na mesma conta não compartilham a contagem. Se quiser escolher o namespace você mesmo, defina namespaceId.

Unkey

unkey() guarda a contagem no rate limiting do Unkey, compartilhado por todas as instâncias. Crie uma root key com a permissão ratelimit.*.limit e também a ratelimit.*.create_namespace, para que o Unkey possa criar o namespace na primeira requisição. Depois, defina essa chave como UNKEY_ROOT_KEY. O Blume se comunica com a API REST do Unkey, então você não precisa instalar nada. Enquanto a chave não estiver definida, as rotas contam em memória e o blume build mostra um aviso.

import { unkey } from "blume/ratelimit";

rateLimit: unkey(),

O namespace é docs, a menos que você indique outro com namespace. Indique o nome da variável que guarda a chave com rootKeyEnv:

rateLimit: unkey({ namespace: "acme-docs", rootKeyEnv: "DOCS_UNKEY_ROOT_KEY" }),

O Unkey conta em cada região e compartilha as contagens entre as regiões em instantes. Por isso, uma rajada curta distribuída entre regiões pode deixar passar algumas requisições além do limite. Com uma chave que o Unkey recusa, como uma sem essas permissões, todas as contagens falham, e uma requisição que o armazenamento compartilhado não consegue contar sempre passa. Então, se o servidor registrar Rate limiting failed no log, verifique a chave.

Atrás de um proxy reverso

Vercel, Netlify e Cloudflare informam ao Blume o endereço de cada leitor. Já um servidor node() atrás de um proxy reverso, como nginx ou Caddy, vê todas as requisições chegando do proxy. Assim, todos os leitores compartilham uma única contagem, e um site movimentado atinge o limite para todo mundo. Liste em allowedDomains o host que o proxy atende:

import { node } from "blume/deploy";

deployment: node({
  site: "https://docs.example.com",
  allowedDomains: [{ hostname: "docs.example.com" }],
}),

Essa é a opção security.allowedDomains do Astro: quando o cabeçalho Host ou X-Forwarded-Host de uma requisição corresponde a uma das entradas, o Astro pega o endereço do leitor do primeiro valor de X-Forwarded-For. Configure o proxy para repassar o host do site e substituir qualquer X-Forwarded-For enviado pelo leitor pelo endereço que o proxy enxerga, como faz o proxy_set_header X-Forwarded-For $remote_addr; do nginx. Um proxy que, em vez disso, acrescenta valores ao cabeçalho deixa o leitor escolher o próprio endereço e ganhar uma contagem nova a cada requisição. Deixe allowedDomains sem definir quando os leitores acessam o servidor diretamente.

Como desativar

Defina rateLimit: false para deixar todas as requisições passarem, por exemplo quando o firewall do seu host já limita essas rotas. Uma requisição cujo endereço o host não consegue identificar sempre passa. O mesmo vale para uma requisição que o armazenamento compartilhado não consegue contar: a falha fica registrada no log, e os leitores nunca são bloqueados por uma queda do armazenamento.

No caso do assistente, use o limite de requisições junto com uma verificação de bots para barrar scripts que distribuem as requisições entre muitos endereços.

Última atualização a

Esta página foi útil?