Service Discovery no Node.js resolve como uma aplicação encontra instâncias de outros serviços sem depender de endereços fixos. Em ambientes com containers, autoscaling e deploys frequentes, IPs mudam e novas réplicas entram ou saem continuamente.
A descoberta pode ser feita pelo cliente, por um proxy ou pela própria plataforma. O objetivo é transformar um nome lógico, como payments, em um conjunto saudável de destinos.
Por que endereços fixos falham
Configurar uma URL única em variável de ambiente funciona em sistemas pequenos, mas cria ponto único de falha e exige alteração a cada mudança. Com várias réplicas, o cliente precisa balancear conexões e reagir a instâncias indisponíveis.
DNS como mecanismo de descoberta
Em Kubernetes e muitas plataformas, o DNS interno já fornece descoberta básica:
const response = await fetch('http://payments.default.svc.cluster.local/health');O nome permanece estável enquanto a plataforma atualiza os endpoints. Consulte DNS no Node.js.
Resolução com node:dns
import { resolve4 } from 'node:dns/promises';
const records = await resolve4('payments.internal', { ttl: true });
console.log(records);Ao implementar cache próprio, respeite TTL e trate respostas vazias. Não mantenha um IP indefinidamente.
Descoberta do lado do cliente
Nesse modelo, o cliente consulta um registro e escolhe uma instância. Ele precisa de:
- cache com expiração;
- balanceamento round-robin ou por carga;
- remoção temporária de destinos com falha;
- timeout e circuit breaker por instância;
- atualização periódica do conjunto.
Descoberta por proxy
Um load balancer, sidecar ou service mesh recebe a requisição e escolhe o backend. A aplicação usa um endereço estável e fica mais simples, enquanto a plataforma concentra health checks, mTLS e balanceamento.
Registro de serviços
Ferramentas como Consul mantêm um catálogo de serviços e checks. Uma instância registra nome, endereço, porta e metadados. Ao encerrar, deve remover o registro ou usar TTL/lease para que entradas abandonadas expirem.
Exemplo de catálogo simples
class ServiceRegistry {
#services = new Map();
register(name, instance) {
const list = this.#services.get(name) ?? [];
this.#services.set(name, [...list, instance]);
}
getHealthy(name) {
return (this.#services.get(name) ?? []).filter((item) => item.healthy);
}
}Esse código é didático. Em produção, o catálogo precisa ser distribuído, consistente o suficiente e tolerante a falhas.
Health checks
Uma instância deve ser anunciada somente quando estiver pronta. Diferencie:
- liveness: o processo ainda funciona;
- readiness: pode receber tráfego;
- startup: concluiu inicialização lenta.
Veja Health Checks no Node.js.
Balanceamento e keep-alive
Conexões persistentes podem manter tráfego preso a poucas instâncias. Pools precisam acompanhar alterações no conjunto e eliminar destinos removidos. Consulte HTTP Keep-Alive no Node.js.
Falhas de DNS
Trate ENOTFOUND, EAI_AGAIN e timeouts como situações diferentes. Um retry curto com jitter pode ajudar em falha transitória, mas não deve exceder o deadline da requisição.
Stale-while-revalidate
Quando a fonte de descoberta está temporariamente indisponível, pode ser melhor usar o último conjunto conhecido por um período limitado. Defina idade máxima e monitore quando dados stale forem usados.
Metadados e zonas
O catálogo pode incluir região, zona, versão e capacidade. Prefira instâncias locais para reduzir latência, mantendo fallback para outra zona quando necessário.
Deploy gradual
Metadados permitem separar versões stable e canary. O roteador direciona uma porcentagem pequena à nova versão e aumenta gradualmente após observar métricas.
Segurança
- autentique registros e consultas ao catálogo;
- não aceite endpoints fornecidos por usuários;
- use mTLS quando o risco exigir;
- limite metadados expostos;
- proteja tokens de registro;
- valide portas e esquemas permitidos.
Observabilidade
Monitore quantidade de instâncias, idade do cache, falhas de resolução, tempo de descoberta e distribuição de tráfego. Logs devem indicar serviço lógico e destino escolhido sem expor credenciais.
Erros comuns
- cachear DNS para sempre;
- ignorar TTL;
- anunciar instância antes de estar pronta;
- não remover conexão para endpoint encerrado;
- repetir chamadas sem deadline;
- depender de um catálogo sem estratégia de fallback;
- misturar descoberta com autorização.
Conclusão
Service Discovery no Node.js permite localizar serviços em ambientes dinâmicos sem endereços fixos. DNS da plataforma costuma ser a melhor primeira opção; catálogos dedicados são úteis quando metadados, zonas e checks avançados são necessários.
Combine descoberta com health checks, pools atualizáveis, timeouts e observabilidade. Consulte a documentação DNS do Node.js e a documentação de Service Discovery do Consul.



