Geolocalização de IP no Cloudflare Workers: cache e cold starts
Geolocalização de IP no Cloudflare Workers significa ler dados de localização de um visitante dentro de um Worker, seja a partir do objeto embutido request.cf, seja chamando uma API externa de inteligência de IP a partir da borda. As duas abordagens respondem a perguntas diferentes, e vale entender o comportamento de cache e de cold start de cada uma antes de construir sobre elas.
O que o Workers oferece de graça
Toda requisição que chega a um Worker traz um objeto request.cf preenchido pela Cloudflare. Ele inclui o país, a cidade, a região, as coordenadas, o fuso horário, o ASN e a organização do AS do visitante, além do campo colo, que nomeia o data center que tratou a requisição. O cabeçalho CF-IPCountry também traz o código do país. Como esses dados são anexados antes de o seu código rodar, não há subrequisição extra nem latência extra.
O limite é o escopo. O request.cf descreve o cliente que se conectou na requisição atual e nada mais. Ele não pode dizer nada sobre um endereço IP que aparece em uma linha de log, em um campo de formulário, no payload de um webhook ou em uma cadeia X-Forwarded-For, e não traz sinais de reputação, como flags de VPN, Tor ou abuso. Quando você precisa enriquecer um endereço arbitrário, você está chamando uma API, e é aí que começam as decisões de cache.
Cache de dados de enriquecimento na borda
Uma consulta de IP feita a partir de um Worker é uma subrequisição, então toda consulta sem cache adiciona uma ida e volta de rede ao caminho da requisição. A Cloudflare oferece vários lugares para armazenar o resultado: a Cache API (por data center, não replicada globalmente), o KV (legível globalmente, mas eventualmente consistente, com gravações que levam tempo para se propagar) e os Durable Objects, quando você precisa de uma única cópia coordenada. Nenhum deles é um cache global pronto para uso, então escolha pelo que você consegue tolerar: a Cache API é a mais simples e rápida para consultas de leitura intensiva, enquanto o KV serve para valores que você quer visíveis de qualquer localização.
A decisão de projeto mais útil é o tempo de vida por campo, porque os dados de inteligência de IP não envelhecem de modo uniforme. As atribuições de país e de ASN mudam devagar, já que os blocos de endereços são realocados ao longo de meses ou anos, então um TTL de muitas horas é razoável. As flags de reputação são diferentes. Os feeds de VPN, Tor e abuso do ipto são atualizados a cada 6 horas, e seus conjuntos de IP e ASN diariamente, então armazenar uma flag como is_tor por mais do que algumas horas significa servir respostas mais antigas do que a própria fonte. Uma divisão prática é armazenar os fatos de rede (asn, asn_org, país, cidade) por cerca de um dia e as flags (is_vpn, is_tor, is_abuser, is_datacenter) por no máximo o intervalo do feed.
- Use como chave do cache o IP normalizado (para IPv6, considere usar a /64 se o seu caso de uso for por rede e não por host).
- Armazene também resultados negativos, para que consultas repetidas de um endereço não listado não acessem a API toda vez.
- Nunca armazene resultados bogon sob uma chave pública por acidente: um endereço privado como
10.0.0.1pode ser respondido localmente, sem nenhuma chamada de API.
Cold starts no Workers
Os Workers rodam em isolates do V8 e não em contêineres, então um cold start costuma ser questão de milissegundos, e não das centenas de milissegundos familiares das funções baseadas em contêineres. Seu código ainda paga pela própria inicialização: um bundle grande, parsing pesado em nível de módulo de uma tabela de consulta grande ou awaits de nível superior acontecem na primeira requisição a um isolate novo. A solução é a de sempre: mantenha o bundle pequeno, evite construir grandes estruturas em memória na inicialização e prefira uma única chamada de API pequena a embutir um banco de dados de geolocalização inteiro no Worker.
Os pings de aquecimento que as pessoas usam com serverless tradicional são, em sua maior parte, desperdício aqui. Os isolates são criados e removidos no cronograma da Cloudflare, um ping atinge apenas uma localização, e o custo de um cold start é pequeno o bastante para que armazenar o resultado da consulta importe muito mais do que manter o isolate vivo. Meça primeiro com a análise do Workers e com a sua própria cronometragem em torno da subrequisição antes de otimizar qualquer coisa.
Juntando tudo com o ipto
Um padrão sensato é usar o request.cf para os fatos instantâneos e gratuitos sobre o cliente conectado e chamar uma API de enriquecimento apenas quando precisar de mais. A documentação da API do ipto mostra a resposta da consulta de IP, que retorna país, cidade, ASN, org, currency_code e as flags is_vpn, is_tor, is_abuser, is_datacenter e bogon/bogon_type. É gratuita, sem cadastro, com 1.000 requisições gratuitas por dia, o que basta para prototipar um Worker sem uma etapa de gerenciamento de chaves.
Quando a consulta indica que o endereço pertence a uma rede de hospedagem, você pode seguir para a consulta de ASN para ver quem a opera e quais faixas ela anuncia. Para tráfego sinalizado, o verificador de VPN, Tor e proxy mostra as evidências por trás de is_vpn e is_tor, e o verificador de abuso de IP mostra a pontuação corroborada. Lembre-se de que a localização no nível de cidade é uma estimativa de onde uma rede está registrada ou roteada, e não de onde uma pessoa está sentada, uma limitação explicada em por que a precisão por cidade é limitada.
A borda torna as consultas rápidas, mas não torna os dados subjacentes mais precisos. Trate o request.cf e qualquer resultado de API como a mesma classe de evidência, armazene cada um de acordo com a velocidade com que muda e deixe que a atualidade da fonte, e não a velocidade da borda, decida os seus TTLs.