DNS
Como um nome de domínio vira um endereço IP, quem responde em cada etapa e por que uma mudança de DNS demora a valer para todos.
A maior parte do trabalho com DNS no backend é investigação e configuração de cliente. Você raramente escreve um resolvedor. O que precisa saber é consultar, ler a resposta e entender o que a sua linguagem faz com ela.
Consultar com o dig
O dig mostra a resposta do DNS sem nenhuma camada no meio. A forma curta devolve só o valor:
dig +short api.loja.com.br AA forma completa mostra o TTL restante, na segunda coluna da resposta:
dig api.loja.com.br A;; ANSWER SECTION:
api.loja.com.br. 187 IN A 203.0.113.10O número 187 indica que o resolvedor consultado ainda vai usar essa resposta por 187 segundos. Rodar o comando de novo mostra o número diminuindo, o que prova que a resposta veio do cache.
Três variações resolvem a maior parte das investigações:
# Perguntar a um resolvedor específico, para comparar caches
dig @1.1.1.1 api.loja.com.br A
dig @8.8.8.8 api.loja.com.br A
# Perguntar direto ao servidor autoritativo, sem cache nenhum
dig +short NS loja.com.br
dig @ns1.provedor-exemplo.net api.loja.com.br A
# Refazer o caminho completo a partir da raiz
dig +trace api.loja.com.brResolver um nome pelo código
Os exemplos resolvem os endereços de um nome usando a biblioteca padrão.
import { resolve4 } from "node:dns/promises";
const enderecos = await resolve4("example.com", { ttl: true });
for (const { address, ttl } of enderecos) {
console.log(`${address} (TTL ${ttl}s)`);
}import socket
infos = socket.getaddrinfo("example.com", 443, proto=socket.IPPROTO_TCP)
for _familia, _tipo, _proto, _nome, endereco in infos:
print(endereco[0])package main
import (
"context"
"fmt"
"net"
"time"
)
func main() {
ctx, cancelar := context.WithTimeout(context.Background(), 2*time.Second)
defer cancelar()
enderecos, err := net.DefaultResolver.LookupHost(ctx, "example.com")
if err != nil {
fmt.Println("falha na resolução:", err)
return
}
for _, endereco := range enderecos {
fmt.Println(endereco)
}
}import java.net.InetAddress;
public class Resolver {
public static void main(String[] args) throws Exception {
for (InetAddress endereco : InetAddress.getAllByName("example.com")) {
System.out.println(endereco.getHostAddress());
}
}
}using System.Net;
var enderecos = await Dns.GetHostAddressesAsync("example.com");
foreach (var endereco in enderecos)
{
Console.WriteLine(endereco);
}O que muda de uma linguagem para outra
As cinco chamadas parecem iguais e se comportam de formas diferentes por baixo.
| Quem resolve | Cache dentro do programa | Ponto de atenção | |
|---|---|---|---|
| Node | dns.lookup, usado pelo fetch e pelo http, chama o sistema operacional. dns.resolve*, do exemplo, fala direto com o servidor DNS | Nenhum | dns.lookup ocupa uma thread do pool interno, que tem 4 por padrão. Um DNS lento atrasa também leitura de arquivos e criptografia |
| Python | O sistema operacional, por getaddrinfo | Nenhum | A chamada bloqueia. No asyncio, ela é executada em uma thread separada |
| Go | Um resolvedor próprio, escrito em Go, que lê a configuração do sistema no Linux | Nenhum | Aceita context, então o tempo limite cobre a resolução |
| Java | O sistema operacional, pela JVM | Sim: 30 segundos para respostas positivas por padrão | Configurações antigas ou com gerenciador de segurança guardam a resposta para sempre |
| C# | O sistema operacional | Nenhum na resolução | O HttpClient mantém conexões abertas sem limite de idade por padrão |
No Node, as duas famílias de função podem dar respostas diferentes para o mesmo nome. dns.lookup respeita o arquivo hosts da máquina e dns.resolve4 o ignora. Isso explica o caso de um nome que funciona no fetch e falha no script de diagnóstico.
O problema real: conexões que duram mais que o DNS
Nenhuma das cinco linguagens guarda o DNS por muito tempo. O endereço antigo sobrevive por outro motivo: o cliente HTTP reaproveita conexões. Enquanto uma conexão estiver aberta, ninguém consulta o DNS de novo, e o programa continua falando com o endereço resolvido horas ou dias antes.
O sintoma clássico é este: o serviço de destino muda de endereço em um deploy ou failover, as instâncias recém-iniciadas funcionam e as que estavam no ar há mais tempo continuam chamando o endereço antigo.
A correção é limitar a idade das conexões, para forçar uma nova resolução de tempos em tempos.
// .NET: recicla as conexões a cada 2 minutos, o que força nova consulta DNS
var handler = new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(2),
};
var cliente = new HttpClient(handler);// Java: define o cache de DNS da JVM em 30 segundos, antes da primeira resolução
java.security.Security.setProperty("networkaddress.cache.ttl", "30");// Go: fecha as conexões ociosas depois de 90 segundos
transporte := &http.Transport{IdleConnTimeout: 90 * time.Second}
cliente := &http.Client{Transport: transporte, Timeout: 5 * time.Second}| Linguagem | O que configurar |
|---|---|
| Node | O tempo de vida das conexões ociosas no agente HTTP da biblioteca em uso |
| Python | Os limites e a expiração do pool da biblioteca (requests, httpx) |
| Go | IdleConnTimeout no http.Transport. Conexões em uso constante não são fechadas por ele |
| Java | networkaddress.cache.ttl e o tempo de vida das conexões do cliente HTTP |
| C# | PooledConnectionLifetime no SocketsHttpHandler |
Lista de revisão
Use esta lista ao revisar código que chama outros serviços ou ao planejar uma mudança de DNS:
No código
- O tempo limite da chamada cobre a resolução do nome, e não só a conexão e a resposta?
- O cliente HTTP tem um limite de idade para as conexões reaproveitadas?
- O pool de conexões do banco tem tempo máximo de vida configurado?
- Em Java, o valor de
networkaddress.cache.ttlé conhecido e adequado? - Uma falha de resolução é registrada no log como erro de DNS, distinta de erro de conexão?
Na operação
- O TTL foi reduzido com antecedência maior que o TTL antigo antes da migração?
- O servidor antigo continua no ar até os caches vencerem?
- A alteração foi conferida no servidor autoritativo com o
dig? - Os registros estão versionados, com histórico de quem alterou?
Prompts para aprofundar
Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.
Investigar um problema de DNS com o dig
Quero treinar o diagnóstico de problemas de DNS pela linha de comando. Primeiro, ensine a ler a saída completa do comando dig: as seções de pergunta, resposta e autoridade, o TTL, os indicadores do cabeçalho e o código de status (NOERROR, NXDOMAIN, SERVFAIL). Explique também as opções +short, +trace e a consulta a um servidor específico com @. Depois simule quatro incidentes, um de cada vez. Em cada um, descreva só o sintoma, deixe que eu diga quais comandos rodaria, mostre a saída que cada comando daria e peça a minha conclusão antes de revelar a causa: 1. "Alterei o registro há duas horas e ainda vejo o endereço antigo." 2. "O site abre na minha máquina e não abre para um cliente." 3. "O nome não resolve de jeito nenhum, e o registro existe no painel." 4. "O serviço resolve dentro do container, mas com um endereço diferente do que aparece fora dele." A cada passo, diga se o comando que escolhi ajuda ou não, e por quê. No final, monte um roteiro de diagnóstico com a ordem de verificação que eu deveria seguir.
Cache de DNS e conexões na minha linguagem
Quero entender como a minha linguagem e as minhas bibliotecas tratam a resolução de DNS, para evitar que a aplicação fique presa a um endereço antigo. Pergunte qual linguagem, qual versão, qual biblioteca de cliente HTTP e qual biblioteca de acesso a banco de dados eu uso. Depois explique, especificamente para esse conjunto: 1. Quem faz a resolução do nome (o sistema operacional ou a própria linguagem) e se existe cache dentro do processo, com o valor padrão. 2. Como o reaproveitamento de conexões do cliente HTTP faz o endereço antigo sobreviver, mesmo sem cache de DNS. 3. Quais opções de configuração controlam o tempo de vida das conexões no cliente HTTP e no pool do banco de dados, com exemplo de código. 4. Se o tempo limite que eu configuro nas chamadas cobre a etapa de resolução do nome. Em seguida, descreva o cenário de um failover de banco de dados em que o nome passa a apontar para outro servidor, e pergunte o que acontece com a minha aplicação nas configurações padrão. Corrija o meu raciocínio e mostre a configuração recomendada. Sempre que citar um valor padrão, diga de qual versão ele vale e recomende que eu confirme na documentação oficial.
Revisar o uso de DNS no meu código
Vou colar abaixo um trecho de código ou de configuração que chama outros serviços pela rede: cliente HTTP, pool de banco de dados, configuração de container ou de orquestrador. Revise com foco em resolução de nomes e conexões de longa duração. Verifique, nesta ordem, e para cada item diga se está correto, incorreto ou ausente: 1. Os destinos são referenciados por nome ou por endereço IP fixo? Há endereços fixos que deveriam ser nomes? 2. O cliente HTTP é reaproveitado? Existe limite de idade para as conexões abertas? 3. O pool de conexões do banco tem tempo máximo de vida e validação antes do uso? 4. Os tempos limite cobrem a resolução do nome, a conexão e a resposta? 5. Uma falha de resolução é tratada e registrada de forma que eu consiga distingui-la de outros erros de rede? 6. Há novas tentativas quando a resolução falha? Com qual intervalo? Para cada problema, explique o incidente de produção que ele pode causar e mostre a correção. Não reescreva o que já está correto. Código ou configuração: [cole aqui]