Fundamentos de Microsserviços
O que define um microsserviço?
Microsserviços representam um estilo arquitetural que decompõe aplicações monolíticas em unidades menores, indepandentes e fracamente acopladas. Cada serviço encapsula uma capacidade de negócio específica e se comunica através de protocolos leves como HTTP/REST ou gRPC. A autonomia de cada serviço permite ciclos independentes de desenvolvimento, deploy e escala.
A evolução arquitetural típica segue o caminho: Monólito → SOA → Microsserviços. No modelo monolítico, toda a aplicação é construída e implantada como uma única unidade, compartilhando base de código e repositório de dados. Com o crescimento, a manutenção se torna complexa e a escalabilidade é comprometida. A arquitetura orientada a serviços (SOA) surgiu como intermediária, promovendo a decomposição em serviços reutilizáveis com interfaces padronizadas, porém sem definir restrições de granularidade. Os microsserviços levam essa ideia adiante com serviços menores, autônomos e com governança descentralizada de dados.
Desafios da adoção de microsserviços
A migração para microsserviços introduz complexidades que precisam ser avaliadas:
- Complexidade sistêmica: A decomposição multiplica o número de componentes, exigindo gestão de comunicação, deploy e monitoramento inter-serviços.
- Overhead de comunicação: Chamadas remotas adicionam latência por serialização e tráfego de rede.
- Consistência de dados: Cada serviço possuindo seu próprio datastore torna transações distribuídas e sincronização de dados mais difíceis.
- Operação e deploy: Múltiplos serviços independentes demandam pipelines de CI/CD robustos e automação de infraestrutura.
- Coordenação entre equipes: Times distintos gerenciando serviços distintos aumentam a necessidade de contratos e comunicação eficaz.
- Governança de serviços: Versionamento, descoberta, balanceamento e tratamento de falhas tornam-se preocupações centrais.
- Complexidade inerente a sistemas distribuídos: Latência de rede, consistência eventual e tolerância a falhas são desafios intrínsecos.
A decisão entre monólito e microsserviços deve considerar o contexto real — nem todo sistema precisa de microsserviços desde o início.
Soluções open-source para microsserviços Java
As três soluções mais adotadas:
Dubbo: Framework RPC de alta performance, originalmente criado pela Alibaba. Oferece descoberta de serviços, balanceamento de carga e tolerância a falhas. Utiliza comunicação baseada em RPC com suporte a múltiplos protocolos e formatos de serialização. A versão 3 incorporou compatibilidade com gRPC e HTTP/2.
Spring Cloud Netflix: Integra componentes open-source da Netflix como Eureka (descoberta), Ribbon (balanceamento), Hystrix (circuit breaker) e Zuul (gateway). Entretanto, desde 2018 a Netflix encerrou o suporte ativo, levando o projeto ao modo de manutenção.
Spring Cloud Alibaba: Solução que integra o ecossistema Alibaba, incluindo Nacos (registro e configuração), Sentinel (controle de fluxo e circuit breaker) e Seata (transações distribuídas). É a solução com maior atividade comunitária atualmente.
| Aspecto | Dubbo | Spring Cloud Netflix | Spring Cloud Alibaba |
|---|---|---|---|
| Comunicação | RPC | HTTP/REST | HTTP/REST + RPC |
| Registro | ZooKeeper/Nacos | Eureka/Consul | Nacos |
| Circuit Breaker | Sentinel | Hystrix | Sentinel/Resilience4j |
| Configuração | Apollo | Spring Cloud Config | Nacos Config |
| Gateway | Higress/APISIX | Zuul/Gateway | Spring Cloud Gateway |
| Transação distribuída | Seata | Não suportado | Seata |
| Maturidade comunitária | Alta | Baixa (mantido) | Alta e crescente |
Componentes essenciais de microsserviços
- Registro de serviços: Gerencia endereços e metadados dos serviços (Eureka, Nacos, Consul, ZooKeeper)
- Configuração centralizada: Gerencia configurações sem reiniciar serviços (Spring Cloud Config, Nacos Config, Apollo)
- Comunicação remota: REST (Feign, RestTemplate) ou RPC (Dubbo, gRPC)
- Gateway de API: Ponto único de entrada com roteamento, segurança e balanceamento (Gateway, Zuul, APISIX)
- **Transação distribuída: Garante consistência entre serviços (Seata)
- Circuit breaker: Isola falhas e previne cascatas (Hystrix, Sentinel, Resilience4j)
- Rastreamento distribuído: Visualiza fluxo de requisições (Zipkin, Jaeger, SkyWalking)
- Monitoramento e logs: Observabilidade do sistema (Prometheus, Grafana, ELK)
Registro e Descoberta de Serviços
Função do registro de serviços
O registro de serviços atua como diretório centralizado para instâncias de microsserviços. Suas responsabilidades incluem:
- Registro: Serviços registram endereço, porta e metadados ao iniciar
- Descoberta: Clientes consultam o registro para localizar instâncias disponíveis
- Balanceamento: Distribui requisições entre múltiplas instâncias do mesmo serviço
- Recuperação de falhas: Detecta instâncias indisponíveis e remove do catálogo
- Governança: Suporta configuração dinâmica, escala e roteamento
Comparação: Eureka vs ZooKeeper vs Nacos
| Característica | Eureka | ZooKeeper | Nacos |
|---|---|---|---|
| Modelo CAP | AP | CP | AP e CP (configurável) |
| Protocolo | HTTP | TCP | HTTP/DNS |
| Auto-proteção | Sim | Não | Sim |
| Verificação de saúde | Heartbeat do cliente | Keep-alive | TCP/HTTP/MYSQL/Heartbeat |
| Foco | Descoberta de serviços | Coordenação distribuída | Descoberta + configuração + gestão |
A diferença fundamental está no teorema CAP: Eureka prioriza disponibilidade (AP), ZooKeeper prioriza consistência (CP), e Nacos permite alternar entre os dois modos.
Princípios de funcionamento do Eureka
- Registro e descoberta: Ao iniciar, um serviço envia suas informações ao Eureka Server, que mantém tudo em memória e expõe endpoints REST para consulta.
- Verificação de saúde: Instâncias enviam heartbeats periódicos (renovação). Se o Server não recebe renovação dentro do prazo, a instância é removida.
- Balanceamento no cliente: O cliente Eureka mantém cache local do catálogo de serviços. Ao chamar outro serviço, obtém a lista de instâncias e aplica balanceamento de carga.
Alta disponibilidade do Eureka Server
- Múltiplas instâncias: Deploy de vários servidores em nós distintos. Falha de um não derruba o sistema.
- Replicação de estado: Cada servidor replica as informações de registro dos demais, mantendo consistência eventual.
- Modo de auto-proteção: Quando o servidor deixa de receber heartbeats acima de um limiar, entra em modo de auto-proteção e não remove instâncias, evitando exclusões indevidas por flutuações de rede.
Configuração Centralizada
Necessidade de um configuration center
Em ambientes com dezenas ou centenas de instâncias, gerenciar configurações manualmente é inviável. Um configuration center permite gerenciar variáveis de ambiente, strings de conexão, níveis de log e parâmetros de negócio de forma centralizada, com atualização dinâmica sem reinicialização.
Opções para Spring Cloud
- Spring Cloud Config: Solução oficial, armazena configs em Git/SVN com API REST
- Apollo: Open-source pela Ctrip, oferece gestão granular de permissões, notificação de mudanças e release canário
- Nacos: Plataforma da Alibaba combinando registro de serviços e configuração
- Consul: Descoberta de serviços com armazenamento key-value para configuração
- etcd: Armazenamento key-value distribuído com consenso Raft
- ZooKeeper: Coordenação distribuída com suporte a configuração
Mecanismo de long-polling do Nacos
O Nacos utiliza long-polling para detecção de mudanças de configuração. O fluxo:
- O cliente envia uma requisição de verificação ao servidor. Se não houver mudanças, o servidor segura a conexão em uma fila de espera.
- Durante a espera, se a configuração mudar (via dashboard ou API), o servidor responde imediatamente com os dados atualizados.
- Se nenhuma mudança ocorrer dentro do timeout, o servidor responde vazios e o cliente reenvia a requisição.
- O servidor mantém um mapeamento entre chaves de configuração e conexões em espera, permitindo notificação seletiva.
Essa abordagem combina baixa latência de detecção com uso eficiente de recursos, evitando manter milhares de conexões persistentes.
Comunicação Remota
HTTP vs RPC
HTTP é um protocolo de camada de aplicação focado em transferência de dados. RPC é um padrão de comunicação para invocação remota de métodos. Frameworks RPC modernos como gRPC e Dubbo3 utilizam HTTP/2 como protocolo de transporte subjacente.
| Critério | HTTP | RPC |
|---|---|---|
| Modelo | Request-response | Invocação de método |
| Formato de dados | Texto (JSON, XML) | Binário (Protobuf, Hessian) |
| Definição de interface | RESTful conventions | IDL (Protobuf, Thrift) |
| Performance | Menor overhead de desenvolvimento | Menor latência e maior eficiência |
| Caso de uso | APIs públicas, integração web | Comunicação interna de alta performance |
Feign vs Dubbo
| Aspecto | Feign | Dubbo |
|---|---|---|
| Protocolo | HTTP/REST | RPC (TCP personalizado, gRPC) |
| Abordagem | Cliente HTTP declarativo | Framework de serviços distribuído |
| Governança | Depende de componentes externos | Nativo (registro, balanceamento, tolerância a falhas) |
| Ecossistema | Spring Cloud | Próprio com componentes integrados |
Feign: cliente HTTP declarativo
Feign simplifica chamadas HTTP através de interfaces anotadas, integrando Ribbon para balanceamento e Hystrix para tolerância a falhas.
@FeignClient(name = "user-service", url = "${services.user.url}")
public interface UserRemoteClient {
@GetMapping("/api/users/{userId}")
ResponseEntity<UserDto> fetchUser(@PathVariable("userId") String userId);
}
Otimize o primeiro chamado do Feign
O primeiro chamado do Feign pode ser lento devido à inicialização preguiçosa do Ribbon (lazy loading), que carrega o catálogo de serviços sob demanda. Solução: ative o carregamento antecipado.
ribbon:
eager-load:
enabled: true
clients: user-service, order-service
Propagação de credenciais no Feign
Implemente RequestInterceptor para injetar headers de autenticação nas requisições do Feign:
@Configuration
public class FeignAuthInterceptorConfig {
@Bean
public RequestInterceptor authHeaderInterceptor() {
return requestTemplate -> {
HttpServletRequest currentRequest = getCurrentHttpRequest();
if (currentRequest != null) {
String authHeader = currentRequest.getHeader("Authorization");
if (authHeader != null) {
requestTemplate.header("Authorization", authHeader);
}
}
};
}
private HttpServletRequest getCurrentHttpRequest() {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
if (attrs instanceof ServletRequestAttributes) {
return ((ServletRequestAttributes) attrs).getRequest();
}
return null;
}
}
Algoritmos de balanceamento de carga
- Round Robin: Distribuição sequencial cíclica entre instâncias
- Weighted Round Robin: Variação com pesos atribuídos por capacidade
- Random: Seleção aleatória uniforme
- Weighted Random: Aleatório ponderado por peso
- Least Connections: Direciona para a instância com menos conexões ativas
- Consistent Hash: Hash de atributo da requisição (IP, URL) mapeado para instância
Tolerância a Falhas
Cascade failure e service avalanche
Quando um serviço falha e seus chamadores continuam enviando requisições e retries, a pressão se acumula nos serviços downstream. O efeito cascada pode derrubar serviços subsequentes e eventualmente comprometer todo o sistema. Medidas preventivas: alta disponibilidade, rate limiting, circuit breakers e degradation.
Circuit breaker e service degradation
Circuit breaker: Monitora chamadas a um serviço. Quando a taxa de erro ou latência ultrapassa um limiar, o circuito abre e subsequentes chamadas falham rapidamente sem reaching o serviço. Após um período, entra em modo half-open para testar recuperação.
Service degradation: Em cenários de sobrecarga ou falha, o sistema substitui funcionalidades não essenciais por respostas simplificadas ou padrão, preservando operações críticas.
Implementações de circuit breaker
| Solução | Origem | Status |
|---|---|---|
| Hystrix | Netflix | Modo manutenção |
| Resilience4j | Comunidade | Ativo, leve |
| Sentinel | Alibaba | Ativo, com dashboard |
Mecanismos do Hystrix
@Service
public class PaymentService {
@HystrixCommand(
commandKey = "processPayment",
fallbackMethod = "handlePaymentFallback"
)
public PaymentResult processPayment(PaymentRequest req) {
return paymentRemoteClient.charge(req);
}
private PaymentResult handlePaymentFallback(PaymentRequest req, Throwable cause) {
log.warn("Fallback acionado para pagamento: {}", req.getTxId(), cause);
return PaymentResult.deferred(req.getTxId());
}
}
Principais mecanismos do Hystrix: circuit breaker com limiares configuráveis, fallback methods, cache de respostas, batching de requisições, isolamento por thread pool e métricas em tempo real.
Controle de fluxo com Sentinel
@Service
public class InventoryService {
@SentinelResource(
value = "checkStock",
blockHandler = "handleBlock",
fallback = "handleFallback"
)
public StockInfo checkStock(String sku) {
return inventoryRepository.findBySku(sku);
}
public StockInfo handleBlock(String sku, BlockException ex) {
return StockInfo.unavailable(sku);
}
public StockInfo handleFallback(String sku, Throwable t) {
return StockInfo.empty(sku);
}
}
Configuração programática de regras:
@PostConstruct
public void setupFlowRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule stockRule = new FlowRule();
stockRule.setResource("checkStock");
stockRule.setCount(50);
stockRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
stockRule.setLimitApp("default");
rules.add(stockRule);
FlowRuleManager.loadRules(rules);
}
O Sentinel utiliza sliding window algorithm para controle de fluxo, dividindo o tempo em janelas que deslizam conforme passa o tempo, permitindo estatísticas mais precisas que o fixed window counter.
Para rate limiting em cluster, o Sentinel usa uma arquitetura Token Server/Token Client, onde clientes solicitam tokens ao servidor central que decide com base nas regras globais.
Gateway de API
Função do API Gateway
O gateway atua como front controller para o cluster de microsserviços: roteamento dinâmico, balanceamento de carga, autenticação e autorização centralizadas, caching de respostas, transformação de protocolos, rate limiting, observabilidade e versionamento de API.
Spring Cloud Gateway
Componentes centrais:
- Route: Define padrão de match e destino (URI, filtros, predicados)
- Predicate: Condição de match (Path, Method, Header, Query, etc.)
- Filter: Transforma request/response (add header, retry, rate limit)
spring:
cloud:
gateway:
routes:
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/api/users/**
- Method=GET,POST
filters:
- AddRequestHeader=X-Gateway-Source,scg
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
O gateway utiliza o modelo reativo baseado em WebFlux, processando requisições de forma não-bloqueante através de uma cadeia de filtros.
Rastreamento Distribuído
Motivação para distributed tracing
Em topologias com dezenas de serviços, uma requisição pode atravessar múltiplos hops. Sem tracing, diagnosticar latência ou erros requer correlação manual de logs dispersos. O tracing distribuído propaga um trace ID entre serviços, permitindo visualizar o fluxo completo, identificar gargalos e mapear dependências.
Soluções integráveis com Spring Cloud
- Zipkin: Open-source pelo Twitter, integra-se com Spring Cloud Sleuth
- Jaeger: Open-source pela Uber, projeto CNCF
- SkyWalking: Projeto Apache, APM com suporte a múltiplas linguagens
- Pinpoint: Open-source pela Naver, focado em Java e .NET
O Spring Cloud Sleuth injeta trace ID e span ID nos headers HTTP e no MDC (Mapped Diagnostic Context) para propagação automática entre serviços.
Transações Distribuídas
Modos do Seata
- AT (Automatic Transaction): Modo padrão. O Seata intercepta SQL e gera undo logs automaticamente. Compensação reversa na fase de rollback. Requer pouco esforço de desenvolvimento.
- TCC (Try-Confirm-Cancel): O desenvolvedor implementa três operações por recurso. Try reserva recursos, Confirm confirma, Cancel desfaz. Oferece isolamento mais forte.
- SAGA: Baseado em eventos, cada serviço executa e publica eventos. Compensações são definidas para cada etapa. Adequado para fluxos longos.
- XA: Protocolo two-phase commit nativo do banco. Requer suporte do banco de dados a XA.
Arquitetura do Seata
Três componentes principais:
- Transaction Coordinator (TC): Mantém estado do global transaction e coordena commit/rollback entre participantes
- Transaction Manager (TM): Define início, commit ou rollback do global transaction
- Resource Manager (RM): Gerencia recursos locais de cada participante, registra branch transactions e executa commit/rollback
Fluxo resumido:
- TM inicia global transaction, recebe XID (global transaction ID)
- XID é propagado via contexto para cada serviço participante
- Cada RM registra branch transaction no TC
- RMs executam lógica local e geram undo logs (AT) ou reservam recursos (TCC)
- TM solicita commit ou rollback global ao TC
- TC notifica cada RM para commitar ou compensar
- TC atualiza estado final e notifica o TM
O XID é propagado via headers HTTP, contexto de thread ou mensagem em filas, dependendo do protocolo de comunicação.
Observabilidade: Monitoramento e Logs
Monitoramento com Prometheus e Grafana
O Prometheus coleta métricas via HTTP pull (scraping) em intervalos configuráveis, armazenando como time-series com labels multidimensionais. O Grafana consome essa API para construir dashboards visuais com gráficos, alertas e anotações.
Métricas típicas de microsserviços: conatdores de requisições, histograms de latência, gauges de conexões ativas, JVM metrics (heap, threads, GC).
Centralização de logs com ELK
- Elasticsearch: Engine de busca e análise distribuída, armazena e indexa logs
- Logstash: Pipeline de ingestão que coleta, filtra, transforma e encaminha logs
- Kibana: Interface visual para consulta, agregação e dashboards
Fluxo: microsserviços → output para stdout/arquivo → Logstash/Filebeat coleta → Elasticsearch indexa → Kibana visualiza.
Alternativas: Fluentd (coletor leve), Loki (indexação por labels apenas, não conteúdo completo), Graylog (stack alternativo com pipeline próprio).