Ao final deste artigo você vai conseguir estimar o piso físico de latência entre seus usuários e seus servidores, medir onde o tempo realmente vai e escolher entre CDN, edge functions, roteamento por região e réplicas de leitura para reduzir a espera.
O problema: servidor longe do usuário
Pense num SaaS hospedado em us-east-1 (Virgínia, EUA) com usuários espalhados pelo Brasil. Quem está em São Paulo tem uma experiência razoável. Quem está em Manaus ou Belém, em redes de operadoras regionais, costuma sentir mais lentidão, e um timeout ocasional não é raro.
Nem sempre a culpa é do código. Os dados viajam pela fibra, a velocidade tem um teto físico e a rota real raramente é uma linha reta. Servidor mais potente não encurta distância. O que ajuda é aproximar o conteúdo e a lógica do usuário.
A física: calcule o piso
A luz na fibra óptica anda a cerca de dois terços da velocidade no vácuo, algo como 200.000 km/s, ou 200 km por milissegundo. Isso dá uma regra de bolso útil: cada 100 km de distância custam cerca de 0,5 ms só na ida, e 1 ms no RTT (round trip time, o ciclo de ida e volta).
RTT mínimo (ms) = 2 × distância (km) / 200
Com distâncias aproximadas em linha reta:
| Trecho | Distância aprox. | RTT mínimo teórico |
|---|---|---|
| São Paulo a Manaus | 2.700 km | cerca de 27 ms |
| São Paulo a Belém | 2.200 km | cerca de 22 ms |
| São Paulo a Virgínia | 7.700 km | cerca de 77 ms |
| São Paulo a Frankfurt | 9.800 km | cerca de 98 ms |
Esses números são o piso, só de propagação. A latência real é maior porque o cabo não segue linha reta, passa por roteadores e pontos de troca de tráfego e sofre com congestionamento. Como ordem de grandeza, o valor medido costuma ficar bem acima do piso, e só a medição no seu caso diz quanto.
Quantos RTTs uma requisição gasta
O que machuca de verdade é que uma requisição web não gasta um RTT, gasta vários em sequência. Em uma conexão nova por HTTPS sobre TCP, a conta inclui:
- Consulta DNS, se não estiver em cache.
- Handshake TCP, 1 RTT.
- Handshake TLS 1.3, 1 RTT (no TLS 1.2 são 2).
- A requisição HTTP e a resposta, 1 RTT, mais o tempo de processamento no servidor.
Ou seja, pelo menos 3 RTTs antes de o primeiro byte útil chegar. Com RTT de 100 ms, são 300 ms de espera só em rede, mesmo com um servidor instantâneo. Daí vêm as estratégias mais eficazes: reaproveitar conexões (keep-alive, HTTP/2), usar HTTP/3 com QUIC, que junta transporte e criptografia no handshake, e terminar a conexão num ponto próximo do usuário, que é exatamente o que um CDN faz. O handshake passa a ser com o nó de borda, a poucos milissegundos, e o nó de borda mantém conexões quentes com a origem.
Meça antes de otimizar
Antes de qualquer mudança, descubra onde o tempo está indo. O curl mostra a quebra de uma requisição:
curl -o /dev/null -s -w \
"dns: %{time_namelookup}s\ntcp: %{time_connect}s\ntls: %{time_appconnect}s\nttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n" \
https://api.exemplo.com/health
Se o ttfb for alto mas o tls for baixo, o gargalo está no servidor ou no banco, e levar o conteúdo ao edge não resolve. Se o tcp e o tls já são altos, a distância é o problema. Rode de lugares diferentes (a máquina de um colega em outra região, uma VM em outra região, ou uma ferramenta de monitoramento sintético) e acompanhe o percentil 95 por região, não só a média.
CDN: conteúdo estático perto do usuário
Um CDN guarda cópias de arquivos estáticos (imagens, CSS, JavaScript, vídeos) em nós espalhados. A primeira requisição vai à origem, as seguintes são atendidas pelo nó mais próximo até o cache expirar. Cloudflare, CloudFront, Akamai e Fastly seguem esse princípio.
Um exemplo em Terraform para o CloudFront na frente de uma aplicação, usando uma política de cache gerenciada em vez do bloco forwarded_values, que está obsoleto:
data "aws_cloudfront_cache_policy" "optimized" {
name = "Managed-CachingOptimized"
}
resource "aws_cloudfront_distribution" "app" {
enabled = true
is_ipv6_enabled = true
http_version = "http2and3"
origin {
domain_name = "origem.exemplo.com"
origin_id = "app"
custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "https-only"
origin_ssl_protocols = ["TLSv1.2"]
}
}
default_cache_behavior {
target_origin_id = "app"
viewer_protocol_policy = "redirect-to-https"
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD"]
cache_policy_id = data.aws_cloudfront_cache_policy.optimized.id
compress = true
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
O price_class define em quais regiões de borda a distribuição usa, e cada classe tem custo diferente. Confira quais classes cobrem a América do Sul antes de escolher, porque nem todas incluem os nós brasileiros.
Um cuidado com cache. Se você cacheia app.js por um ano e lança uma versão nova, os usuários continuam vendo a antiga. A solução é nomear arquivos com hash do conteúdo (app.3f9a1c.js) e dar cache longo e imutável a eles, enquanto o HTML que os referencia tem cache curto.
Edge functions: lógica leve perto do usuário
O CDN resolve o estático. Para decisões simples em cima da requisição, como redirecionar, reescrever cabeçalhos, autenticar um token ou fazer teste A/B, existem funções que rodam no próprio nó de borda. Um exemplo com Cloudflare Workers:
export default {
async fetch(request) {
const url = new URL(request.url);
const pais = request.cf?.country;
const origem = pais === "BR"
? "https://api-br.exemplo.com"
: "https://api-us.exemplo.com";
return fetch(origem + url.pathname + url.search, request);
},
};
A decisão é tomada no nó de borda, sem viagem até a origem. Alternativas equivalentes são CloudFront Functions e Lambda@Edge na AWS, e Vercel e Netlify Edge Functions. Cada plataforma tem limites próprios de tempo de execução, memória e APIs disponíveis, então leia a documentação antes de portar lógica para lá. Em geral, o edge serve para código curto e sem estado, e não para consultas pesadas a banco central nem para rodar modelos grandes de IA.
Roteamento por latência entre regiões
Se a lógica precisa mesmo rodar perto do usuário, você pode ter a aplicação em mais de uma região e deixar o DNS escolher a melhor. O Route 53 tem roteamento por latência, que direciona cada usuário para a região com menor latência medida a partir da rede dele:
resource "aws_route53_record" "api_sa" {
zone_id = aws_route53_zone.main.zone_id
name = "api.exemplo.com"
type = "A"
set_identifier = "sa-east-1"
latency_routing_policy {
region = "sa-east-1"
}
alias {
name = aws_lb.api_sa.dns_name
zone_id = aws_lb.api_sa.zone_id
evaluate_target_health = true
}
}
resource "aws_route53_record" "api_us" {
zone_id = aws_route53_zone.main.zone_id
name = "api.exemplo.com"
type = "A"
set_identifier = "us-east-1"
latency_routing_policy {
region = "us-east-1"
}
alias {
name = aws_lb.api_us.dns_name
zone_id = aws_lb.api_us.zone_id
evaluate_target_health = true
}
}
O exemplo assume que os balanceadores aws_lb.api_sa e aws_lb.api_us já existem. O roteamento por geolocalização é outra coisa: ele decide pelo país ou continente do usuário, o que serve mais para requisitos legais de dados do que para desempenho.
Dados: o gargalo real do multirregião
Subir a aplicação em duas regiões é a parte fácil. O difícil é o banco. Se todas as regiões escrevem em um banco único, as escritas continuam atravessando o oceano. As opções comuns:
- Réplicas de leitura em outras regiões (RDS, Aurora Global Database, Cloud SQL). As leituras ficam locais e rápidas, e as escritas vão para a região principal.
- Cache regional (Redis ou Valkey) para os dados lidos com frequência.
- Bancos distribuídos pensados para multirregião, que trazem outros trade-offs de consistência e custo.
O preço das réplicas é o atraso de replicação. Um usuário pode gravar um dado e, logo em seguida, não vê-lo numa leitura feita na réplica. Para fluxos que exigem leitura do que acabou de ser escrito, direcione essa leitura para a região principal por alguns segundos, ou sirva a sessão dele da região de escrita. Para dados críticos como saldo e estoque, leia sempre da principal.
Armadilhas comuns
Otimizar sem medir. Mover a aplicação para o edge quando o gargalo era uma consulta lenta ao banco não muda nada. Meça o ttfb e o tempo de cada camada primeiro.
Edge function com lógica pesada. A promessa do edge é decisão rápida. Código que demora centenas de milissegundos ou depende de um banco distante perde a vantagem.
Complexidade sem público. Se os usuários estão todos na mesma região da sua infraestrutura, o ganho é pequeno, e multirregião vira custo de operação sem retorno. Um CDN na frente do conteúdo estático, esse sim, quase sempre compensa.
Próximos passos
O caminho mais barato costuma ser este: ponha um CDN na frente do que é estático, meça por região, e só depois avalie edge functions ou uma segunda região. Para descrever essas peças em código, veja Terraform: primeiros passos. Para acompanhar a latência por região em produção, o artigo de monitoramento com Prometheus e Grafana mostra como coletar percentis.
Quer aplicar isso na sua empresa? Marque uma conversa de 45 minutos em https://iauaicloud.com.br/consultoria