Saltar para o conteúdo
EuroVPSEuroVPS

Rate limit no caminho caro, não no crawler

Encontre os URL que custam trabalho real ao seu site e depois limite aí os crawlers com stick tables do HAProxy e um 429, sem prejudicar a pesquisa nem os visitantes.

Por EuroVPS Engineering

5 min de leitura
Rate limit no caminho caro, não no crawler

Bloquear bots é fácil e normalmente errado. Os motores de busca trazem-lhe visitantes, as pré-visualizações de links trazem-lhe cliques, e até os crawlers de IA agressivos são muitas vezes tráfego que prefere abrandar a excluir. A melhor abordagem é encontrar onde os crawlers lhe custam realmente dinheiro, que é um punhado de caminhos sem cache e pesados para a base de dados, e controlar o ritmo aí, no load balancer. É assim que o fazemos.

Descubra o que é caro antes de escrever uma regra

O custo vive nos caminhos que falham a cache e chegam ao PHP e à base de dados: sitemaps gerados na hora, pesquisa, navegação por facetas em que cada combinação de filtros é uma query nova, e tudo o que tenha uma query string que a cache não conhece.

O seu access log já lhe diz quais são. Se o log regista o tempo do pedido (o $request_time do nginx, por exemplo, como último campo), some o tempo gasto por caminho:

awk '{split($7, p, "?"); t[p[1]] += $NF; n[p[1]]++}
     END {for (u in t) printf "%10.1f s %8d req  %s\n", t[u], n[u], u}' access.log \
  | sort -rn | head -20

Depois veja quem o está a gastar, por user agent, nesses caminhos:

awk -F'"' '$2 ~ /sitemap|search|filter=/ {print $6}' access.log \
  | sort | uniq -c | sort -rn | head -20

Duas listas, o trabalho de uma noite, e sabe exatamente onde uma regra vai compensar.

Rate limit com stick tables do HAProxy

O HAProxy consegue contar ritmos de pedidos por cliente e por user agent em memória, à velocidade da linha, e agir sobre eles. Uma configuração mínima que protege apenas os caminhos caros:

backend st_src
    stick-table type ipv6 size 200k expire 10m store http_req_rate(10s)

backend st_ua
    stick-table type string len 128 size 20k expire 10m store http_req_rate(10s)

frontend fe_web
    # bind lines and certificates as usual
    acl expensive path_beg /sitemap /search
    acl expensive url_sub -i filter=
    http-request track-sc0 src table st_src if expensive
    http-request track-sc1 req.fhdr(user-agent) table st_ua if expensive
    http-request deny deny_status 429 hdr Retry-After 60 if expensive { sc_http_req_rate(0) gt 20 }
    http-request deny deny_status 429 hdr Retry-After 60 if expensive { sc_http_req_rate(1) gt 60 }

Três escolhas de desenho importam aqui. Só os caminhos caros são seguidos, por isso nada mais no site é tocado. A resposta é um 429 com um header Retry-After, que os crawlers bem comportados entendem como «abranda e volta mais tarde», não como um erro pelo qual o vão penalizar. E a segunda tabela conta por user agent, o que apanha um crawler espalhado por muitos endereços que escaparia a um limite por endereço. Os limiares acima são indicativos: defina os seus a partir do que o caminho consegue realmente servir sem cache.

Identifique os crawlers com cuidado

Faça correspondência dos user agents de forma lata

Os crawlers alteram o formato das suas strings de user agent, acrescentando tokens de versão, URL ou novos nomes de produto. Uma regra que faz correspondência exata da string inteira deixa de funcionar no dia em que ela muda. A correspondência por substring na parte estável (hdr_sub(user-agent) -i <name>) continua a funcionar.

Não bloqueie o motor de busca por acidente

Verifique um crawler antes de o tratar de forma especial. Os grandes motores de busca publicam como: uma consulta de reverse DNS ao endereço do cliente deve devolver um hostname no domínio deles, e uma consulta direta a esse hostname deve devolver o mesmo endereço.

host <client-address>        # should return a name in the engine's published domain
host <name-returned-above>   # should return the same client address

Os crawlers genuínos ficam então sujeitos a rate limit nos caminhos caros como toda a gente, e continuam a rastrear livremente o resto do site. Os impostores não recebem favores.

Rejeite as formas que nunca são legítimas

Alguns padrões de pedidos não têm nenhuma utilização legítima: URL recodificados vezes sem conta até terem milhares de caracteres, combinações impossíveis de parâmetros, o mesmo percent-encoding aplicado três vezes. Uma única regra no edge rejeita-os antes de custarem o que quer que seja:

http-request deny deny_status 400 if { url_sub -i %2525 }

Ajuste o padrão ao que os seus logs mostram. O ponto é que o load balancer é o sítio mais barato da stack para dizer não.

Proteja o PHP do que passa

Nenhuma regra no edge é perfeita, por isso a camada aplicacional precisa dos seus próprios limites. Em cada pool PHP-FPM, um timeout de terminação impede um pedido patológico de prender um worker durante minutos, e um teto de memória impede-o de crescer sem limite:

request_terminate_timeout = 60s
php_admin_value[memory_limit] = 256M
pm.max_requests = 500

Defina-os em conjunto com as regras do edge, para que as duas camadas concordem sobre o que é um pedido razoável. Entretanto o Varnish continua a servir páginas em cache, por isso leitores e compradores nunca sentem nada disto.

Como o operamos

Nas propriedades de notícias e de e-commerce que operamos, os caminhos de sitemap, pesquisa e listagens filtradas recebem guardas de ritmo desde o primeiro dia, dimensionadas para o que cada site consegue servir sem cache. As novas regras são escritas a partir dos access logs, instaladas em todos os edges da propriedade, e registadas com números de antes e depois para o cliente. Quando aparece um novo crawler, uma regra dirigida pode habitualmente estar em vigor em todos os edges minutos depois de o padrão ser identificado.

Verifique o seu próprio edge

  • Que cinco caminhos custaram mais tempo de PHP e de base de dados na semana passada?
  • Quem os pediu, por user agent?
  • Os seus limites aplicam-se só onde está o custo, ou a todo o site?
  • Responde com 429 e Retry-After, ou com um bloqueio?
  • Quando foi a última vez que alguém confirmou que as regras ainda correspondem ao tráfego real?

Se os crawlers estão a consumir a sua capacidade, podemos ler os seus logs consigo e escrever as regras. Fale com um engenheiro

Related

  • /what-we-do/operations/edge-traffic-control/
  • /what-we-do/data-web/high-availability-web-tiers/
  • /what-we-do/data-web/performance-audits/

Publicado em 12 de outubro de 2026.

Todas as notas de campo