Service discovery e load balancing

1. Fundamentos de Service Discovery em Ambientes Distribuídos

1.1. Definição e importância

Em arquiteturas de microsserviços, os serviços precisam se comunicar entre si para processar requisições. Em um ambiente dinâmico, onde instâncias são criadas e destruídas constantemente (escalonamento horizontal, falhas, deploys), saber onde cada serviço está executando é um problema central. Service discovery é o mecanismo que permite localizar dinamicamente os endereços de rede de serviços disponíveis, sem depender de configurações estáticas.

A importância desse mecanismo é crítica: sem ele, cada serviço precisaria de uma lista fixa de endereços, que se tornaria rapidamente obsoleta em cenários de escalonamento ou falha.

1.2. Desafios da descoberta manual vs. automática

A descoberta manual (arquivos de configuração estáticos, variáveis de ambiente fixas) apresenta diversos problemas:

  • Escalabilidade: a cada nova instância, é preciso atualizar todos os consumidores.
  • Falhas: se uma instância cai, os consumidores continuam tentando se conectar a um endereço morto.
  • Mudanças de endereço: em ambientes cloud, IPs e portas mudam frequentemente.

A descoberta automática resolve esses problemas mantendo um registro centralizado e atualizado de todas as instâncias saudáveis.

1.3. Modelos de descoberta

Client-side discovery: o cliente consulta um service registry (ex: Consul, Eureka) para obter a lista de endereços e aplica o balanceamento localmente. Exemplo:

GET /v1/health/service/api-gateway?passing=true
Resposta:
[
  {"address": "10.0.1.5", "port": 8080},
  {"address": "10.0.1.6", "port": 8080}
]

Server-side discovery: um balanceador de carga centralizado (ex: NGINX, AWS ELB) recebe a requisição e a encaminha para uma instância saudável. O cliente conhece apenas o endereço do balanceador.

2. Padrões de Implementação de Service Discovery

2.1. Registro e descoberta com service registry

Um service registry é um banco de dados distribuído que armazena o mapeamento entre nomes lógicos de serviços e seus endereços físicos. Exemplos populares:

  • Consul: oferece DNS e API HTTP, com suporte a health checks customizados.
  • Eureka: desenvolvido pela Netflix, foco em resiliência e disponibilidade (AP do teorema CAP).
  • etcd: key-value store usado pelo Kubernetes, forte consistência (CP).

Fluxo de registro:

1. Serviço inicia → POST /v1/agent/service/register
   Payload: {
     "Name": "user-service",
     "Address": "10.0.1.10",
     "Port": 3000,
     "Check": {"HTTP": "http://10.0.1.10:3000/health", "Interval": "10s"}
   }
2. Registry armazena e começa a executar health checks periódicos.

2.2. Health checks e heartbeats

Health checks garantem que apenas instâncias saudáveis estejam no pool. Dois mecanismos comuns:

  • Heartbeat: a instância envia periodicamente um sinal de vida (ex: TTL de 30s).
  • Probe: o registry faz requisições HTTP, TCP ou executa scripts no endpoint de saúde.

Exemplo de heartbeat com Consul:

PUT /v1/agent/check/pass?check_id=service:user-service

Se o heartbeat falhar por N tentativas, a instância é marcada como "critical" e removida da descoberta.

2.3. Cache local e fallback

Para reduzir latência e evitar dependência total do registry, os clientes mantêm um cache local da lista de instâncias. Estratégias comuns:

  • Cache com TTL: atualiza a cada 30-60 segundos.
  • Cache com fallback: se o registry estiver indisponível, usa o último snapshot conhecido.

Exemplo de configuração com Spring Cloud Netflix:

eureka.client.cache-refresh-interval-ms: 30000
eureka.client.registry-fetch-interval-seconds: 30

3. Load Balancing: Conceitos e Estratégias

3.1. Balanceamento de carga no lado do cliente

Bibliotecas como Ribbon ou Spring Cloud LoadBalancer permitem que o cliente distribua as requisições entre as instâncias obtidas via service discovery.

Configuração de algoritmo round-robin:

user-service.ribbon.NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule

Vantagem: elimina um ponto único de falha (balanceador central).
Desvantagem: complexidade no cliente.

3.2. Balanceamento de carga no lado do servidor

Balanceadores como NGINX e HAProxy atuam como intermediários. Exemplo de configuração NGINX:

upstream user-service {
    server 10.0.1.10:3000 weight=3;
    server 10.0.1.11:3000 weight=1;
    server 10.0.1.12:3000 backup;
}

server {
    listen 80;
    location /users {
        proxy_pass http://user-service;
    }
}

Vantagem: centraliza a lógica de balanceamento e simplifica clientes.
Desvantagem: pode se tornar gargalo.

3.3. Algoritmos comuns

  • Round-robin: distribui requisições sequencialmente entre instâncias.
  • Least connections: envia para a instância com menos conexões ativas.
  • Consistent hashing: garante que requisições do mesmo cliente sempre vão para a mesma instância (útil para cache).
  • Weighted distribution: instâncias mais potentes recebem mais tráfego.

4. Integração entre Service Discovery e Load Balancing

4.1. Fluxo completo

1. Instância do user-service inicia e se registra no Consul.
2. Instância do api-gateway consulta Consul: "quais endereços do user-service estão saudáveis?"
3. Consul retorna: ["10.0.1.10:3000", "10.0.1.11:3000"]
4. api-gateway aplica load balancing (ex: round-robin) e seleciona 10.0.1.11:3000.
5. Requisição é encaminhada para a instância selecionada.

4.2. Sincronização de lista de endpoints

  • Polling: o cliente consulta o registry em intervalos fixos (ex: 30s). Simples, mas pode ter latência na detecção de mudanças.
  • Watch/Event-driven: o registry notifica os clientes sobre mudanças (ex: Consul watches, Kubernetes endpoints watchers). Menor latência, maior complexidade.

Exemplo de watch com Consul:

GET /v1/health/service/user-service?passing=true&watch=true
(conexão mantida aberta; retorna imediatamente e notifica em mudanças)

4.3. Tolerância a falhas

Combinar service discovery com padrões de resiliência:

  • Retry: se uma requisição falha, tenta a próxima instância da lista.
  • Failover: se o registry falha, usa cache local.
  • Circuit breaker: se uma instância falha repetidamente, para de enviar tráfego para ela por um período.

5. Service Mesh como Abordagem Moderna

5.1. Sidecar proxy e descoberta transparente

Em um service mesh (ex: Istio com Envoy), um proxy sidecar é injetado em cada pod. O sidecar intercepta todo o tráfego de rede e gerencia service discovery e load balancing de forma transparente para a aplicação.

Pod A (user-service)
├── Container: user-service (aplicação)
└── Container: envoy (sidecar)
     ├── Descobre endpoints do Pod B via Istio Pilot
     ├── Aplica load balancing (maglev, round-robin)
     └── Encaminha requisições com mTLS

5.2. Balanceamento avançado com mTLS

O service mesh permite balanceamento com criptografia automática (mTLS) e métricas detalhadas:

  • mTLS: toda comunicação é criptografada e autenticada sem alteração no código.
  • Métricas de tráfego: latência, taxa de erro, volume por serviço.

5.3. Comparação: service mesh vs. bibliotecas embarcadas

Aspecto Bibliotecas embarcadas Service Mesh
Complexidade Baixa (configuração na aplicação) Alta (infraestrutura adicional)
Desempenho Menor overhead Overhead do proxy
Flexibilidade Limitada à linguagem Independente de linguagem
Observabilidade Métricas da aplicação Métricas de rede + aplicação

6. Considerações de Projeto e Boas Práticas

6.1. Estratégias de deploy

Em deploys blue-green ou canary, o service discovery deve ser integrado:

Deploy canary:
1. Nova versão (v2) registra no registry com tag "version=v2".
2. Load balancer envia 10% do tráfego para instâncias com tag "v2".
3. Após validação, remove tag e envia 100%.

6.2. Observabilidade

Métricas essenciais:

  • Tempo de registro: quanto tempo leva para uma instância ficar disponível após o start.
  • Falhas de resolução: quantas vezes a descoberta falhou.
  • Staleness do cache: idade média do cache local.

6.3. Segurança

  • Autenticação no registry: tokens JWT ou mTLS para registrar e consultar.
  • Criptografia: todas as comunicações entre serviços via TLS.
  • Rate limiting: evitar que um cliente sobrecarregue o registry com consultas.

Referências