MÓDULO 09 · 2 SEMANAS · COMUNICAÇÃO ENTRE SERVIÇOS

Comunicação entre Serviços — contratos, protocolos e mensageria

REST, gRPC, GraphQL, reverse proxy, API gateway, service mesh, filas, Kafka, idempotência, service discovery, rate limiting. Como serviços conversam uns com os outros — de forma síncrona, assíncrona, confiável e observável.

Duração ~2 semanas
Conceitos 14 fundamentais
Projeto Malha de Serviços
Pré-requisito Módulos 01, 04, 07, 08
Escalabilidade Disponibilidade Operação

Catorze conceitos que cobrem o espectro completo de comunicação entre serviços: do design de APIs REST maduras ao contrato binário de gRPC, do proxy reverso que senta na borda ao API gateway que centraliza autenticação, roteamento e observabilidade, das filas de mensagem ao Kafka como espinha dorsal de eventos, dos padrões que tornam comunicação assíncrona confiável (outbox, idempotência, at-least-once) ao service mesh que move essas responsabilidades para fora do código. O módulo inclui dois conceitos ausentes da maioria das formações: reverse proxy e API gateway — tratados aqui como disciplinas próprias, não footnotes de load balancing.

01

Taxonomia: síncrono vs assíncrono, request-response vs event-driven

O mapa mental antes dos protocolos. Quando acoplamento temporal é aceitável. Trade-offs de latência, disponibilidade e complexidade entre os paradigmas. Como escolher o modelo de comunicação antes de escolher a tecnologia.

estudar →
02

REST em profundidade — Richardson Maturity Model, HATEOAS, OpenAPI

Os quatro níveis de maturidade REST (Fielding 2000, Richardson 2008). Recursos, verbos HTTP, status codes com semântica precisa. Versionamento de API. OpenAPI 3.1 como contrato executável. O que REST não é.

estudar →
03

gRPC e Protocol Buffers — contrato binário e streaming

Por que binário importa: tamanho, speed, tipo-segurança. Definição de serviço em .proto, geração de código nas 3 linguagens. Quatro modos de streaming. Quando gRPC vence REST e quando perde. Reflection e grpcurl.

estudar →
04

GraphQL — queries flexíveis e o problema do N+1

Schema-first vs code-first. Queries, mutations, subscriptions. O problema do N+1 e DataLoader como solução. Persisted queries, depth limiting, cost analysis. Quando GraphQL faz sentido — e quando REST é melhor.

estudar →
05

Reverse proxy — Nginx, Caddy, Envoy e terminação TLS

O que é um reverse proxy e por que não é só um load balancer. Terminação TLS, header rewriting, caching de resposta, compressão gzip. Nginx como referência histórica, Caddy com TLS automático, Envoy como proxy programável. Configuração idiomática.

estudar →
06

API Gateway — autenticação centralizada, roteamento e rate limiting

API gateway como produto de plataforma sobre reverse proxy. Auth/authz centralizado, rate limiting por cliente e por rota, transformação de payload, roteamento por versão de API, developer portal. Kong, AWS API Gateway, Apigee, APISIX. Quando gateway vira gargalo.

estudar →
07

Service mesh — Istio, Linkerd e o sidecar pattern

Mover retry, circuit breaker, mTLS e observabilidade para fora do código de aplicação. Sidecar proxy (Envoy no Istio, ultralight proxy no Linkerd). Data plane vs control plane. Custo operacional real de um service mesh. Alternativa: eBPF-based mesh (Cilium).

estudar →
08

Message queues — RabbitMQ, SQS e padrões de mensageria

Decoupling temporal como valor fundamental. AMQP: exchanges, bindings, queues. Delivery guarantees: at-most-once, at-least-once, exactly-once. Dead letter queues, TTL, priority queues. RabbitMQ vs SQS vs Redis Streams: quando usar cada um.

estudar →
09

Apache Kafka — log distribuído como espinha dorsal de eventos

O modelo de log append-only (Jay Kreps, "The Log", 2013). Tópicos, partições, consumer groups, offsets. Retenção vs fila. Quando Kafka é a resposta certa e quando é overkill. Kafka Streams e processamento stateful. Schema Registry.

estudar →
10

Padrões de mensageria assíncrona — outbox, saga, choreography

O problema do dual-write e o outbox pattern como solução (Debezium, Transactional Outbox). Saga: orquestração vs coreografia. Compensating transactions. Event sourcing como extensão natural. Quando cada padrão é a resposta certa.

estudar →
11

Idempotência e at-least-once delivery

Por que at-least-once é a garantia padrão de sistemas distribuídos. Chaves de idempotência, deduplicação de mensagem, exactly-once semântica. Idempotência por design vs por controle de estado. Implementação nas 3 linguagens com banco de dados como árbitro.

estudar →
12

Service discovery — DNS, Consul e Kubernetes services

Client-side vs server-side discovery. DNS-based discovery (simples, limitado). Consul: health checks, KV store, service catalog. Kubernetes Services e Endpoints. Headless services. Por que service discovery não é opcional em microsserviços dinâmicos.

estudar →
13

Rate limiting e throttling — algoritmos e implementação

Token bucket vs leaky bucket vs sliding window vs fixed window — trade-offs de precisão e performance. Rate limiting por IP, por usuário, por rota, por plano. Distributed rate limiting com Redis. Headers de rate limit (RFC 6585). Retry-After e backoff exponencial do lado cliente.

estudar →
14

Observabilidade em comunicação distribuída — tracing e correlação

O problema de rastrear uma requisição por 8 serviços. Distributed tracing: trace ID, span ID, propagação de contexto (W3C Trace Context). OpenTelemetry como padrão portável. Jaeger e Zipkin. Correlação com logs e métricas. Service maps e análise de dependência.

estudar →
princípio orientador

A fronteira entre serviços é o lugar onde mais bugs de sistema distribuído nascem e onde mais decisões arquiteturais têm consequências de longo prazo. Escolher REST ou gRPC, fila ou evento, gateway ou mesh — cada uma dessas decisões define quem fica acoplado a quem, quem pode evoluir independentemente, e o que acontece quando uma parte falha. Engenheiros sênior não escolhem protocolos por preferência ou familiaridade; escolhem pelo contrato de acoplamento que cada um estabelece.

Comunicação entre serviços acumula mais decisões de longa duração do que qualquer outro tópico de arquitetura. Protocolos são difíceis de migrar, contratos de mensagem são difíceis de versionar, e o que começa como "só uma chamada REST" vira dependência acoplada por anos. As perguntas abaixo forçam articular o que está em jogo em cada escolha.

REST ou gRPC para comunicação interna entre serviços?

gRPC ganha em performance (binário, HTTP/2 multiplexado), tipagem (contrato .proto gerado), e streaming nativo. Perde em debugging (não é legível sem ferramenta), em adoção por clientes externos (browser não faz gRPC direto sem grpc-web), e em tooling de gateway/proxy que ainda é mais maduro para REST. A regra prática usada na indústria: REST para APIs expostas externamente (cliente browser ou mobile) ou onde legibilidade e flexibilidade de cliente importam; gRPC para comunicação interna entre serviços onde performance e contrato forte valem o custo operacional. Hibridismo é comum e aceitável — API Gateway translating REST externo para gRPC interno.

API Gateway ou Service Mesh — ou os dois?

API Gateway e Service Mesh não são concorrentes — operam em camadas diferentes. Gateway opera na borda norte-sul (tráfego externo entrando no cluster) e gerencia contratos com clientes externos: auth, rate limiting por plano de API, versionamento de rota, developer portal. Service Mesh opera no tráfego leste-oeste (serviço para serviço dentro do cluster) e gerencia resiliência e observabilidade: mTLS, retry, circuit breaker, tracing. Times menores frequentemente começam com só um API Gateway e adiam service mesh até que a escala justifique o custo operacional (Istio tem reputação de complexidade real).

Fila de mensagem ou Kafka?

A distinção fundamental é retenção e reprocessamento. Filas tradicionais (RabbitMQ, SQS) deletam a mensagem após consumo bem-sucedido — boas para comandos, tarefas one-shot, e workloads onde reprocessamento de histórico não é necessário. Kafka retém mensagens pelo tempo configurado (dias, semanas) e permite que novos consumers leiam do início — bom para eventos de domínio que múltiplos sistemas precisam consumir, para audit trail, e para pipelines de dados. Se você precisa de "entregar essa tarefa a um worker", use fila. Se você precisa de "publicar esse evento para quem quiser consumir agora ou daqui 3 dias", use Kafka.

Versionamento de API: URL path, header, ou query string?

URL path (/v1/, /v2/) é o padrão mais adotado porque é explícito, visível em logs, e fácil de rotear no gateway. A crítica é que viola a ideia REST de que URL representa recurso, não versão do contrato. Header (Accept: application/vnd.api.v2+json) é mais "correto" segundo REST puro mas invisível em logs e mais difícil de testar no browser. Query string (?version=2) é conveniente para testes mas raro em produção porque polui caches e logs. Na prática, URL path vence por operabilidade, não por pureza semântica. O que realmente importa: manter v1 funcionando durante a migração — a estratégia de versionamento é secundária ao comprometimento de não quebrar clientes.

Coreografia ou orquestração em sagas distribuídas?

Coreografia: cada serviço reage a eventos e emite os seus próprios. Sem coordenador central. Vantagem: baixo acoplamento, cada serviço evolui independentemente. Desvantagem: o fluxo de negócio fica implícito, distribuído entre vários serviços — difícil de visualizar, testar, e debugar. Orquestração: um orquestrador (pode ser um serviço, pode ser um workflow engine como Temporal ou AWS Step Functions) comanda cada passo e trata falhas centralmente. Vantagem: o fluxo é explícito e observável em um lugar. Desvantagem: o orquestrador vira dependência central. Regra prática: coreografia para fluxos simples com 2-3 participantes; orquestração para fluxos complexos com compensações, timeouts e múltiplos participantes.

O projeto constrói uma malha de três serviços que se comunicam usando os três paradigmas do módulo — REST síncrono, gRPC interno, e mensageria assíncrona — com um API gateway na borda, idempotência nas operações críticas, e distributed tracing ligando tudo.

PROJETO PRÁTICO

Malha de Serviços

Três serviços (pedidos, estoque, notificação) com padrões de comunicação distintos: API REST pública exposta via API gateway (autenticação JWT, rate limiting por cliente), comunicação interna orders → estoque via gRPC (contrato .proto), e notificações enviadas via fila de mensagem com outbox pattern garantindo entrega at-least-once. Um trace ID propaga por toda a cadeia — de ponta a ponta, cada requisição é rastreável no Jaeger.

REQUISITOS
  • API REST pública: POST /orders, GET /orders/{id} — documentada em OpenAPI 3.1
  • API gateway: valida JWT, aplica rate limit de 100 req/min por cliente, roteia para o serviço correto
  • Comunicação orders → estoque via gRPC: .proto compartilhado define o contrato
  • Comunicação orders → notificação via fila: outbox pattern no banco de orders, consumer em notificação
  • Idempotência: POST /orders com mesmo idempotency-key não cria pedido duplicado
  • At-least-once delivery: mensagem de notificação não pode ser perdida mesmo se o consumer cair
  • Dead letter queue: mensagens que falharam 3 vezes vão para DLQ com motivo registrado
  • Distributed tracing: trace ID gerado no gateway propagado em toda a cadeia (W3C Trace Context)
  • Service discovery: serviços se encontram por nome, não por IP hardcoded
  • Cada serviço tem health check próprio e é independentemente deployável
Escalabilidade Disponibilidade Observabilidade
STACK SUGERIDA POR LINGUAGEM
STACK
.NET 10 + ASP.NET Core (REST) + Grpc.AspNetCore (gRPC) + MassTransit + RabbitMQ + Yarp ou NGINX como gateway + OpenTelemetry + Jaeger
ESTRUTURA / NOTAS
  • Orders.Api/ — REST + OpenAPI via Swashbuckle ou Scalar
  • Stock.Service/ — gRPC server com Grpc.AspNetCore; .proto em pasta Contracts/ compartilhada
  • Notification.Service/ — consumer MassTransit + RabbitMQ
  • Gateway/ — YARP com configuração de JWT validation e rate limiting via ASP.NET Core middleware
  • Outbox: MassTransit.EntityFrameworkCore.Outbox para garantia transacional
  • OpenTelemetry SDK com ActivitySource propagando trace ID via W3C TraceContext
STACK
Python 3.13 + FastAPI (REST) + grpcio + grpcio-tools (gRPC) + Celery + RabbitMQ + Traefik como gateway + OpenTelemetry + Jaeger
ESTRUTURA / NOTAS
  • orders/ — FastAPI com OpenAPI gerado automaticamente, idempotency middleware
  • stock/ — gRPC server com servicer gerado de .proto via grpcio-tools
  • notification/ — Celery worker consumindo fila RabbitMQ com acks manuais
  • gateway/ — Traefik com labels de Docker para roteamento, JWT plugin, rate limit
  • Outbox: escrever evento em tabela outbox na mesma transação do pedido; worker separado publica
  • OpenTelemetry: opentelemetry-sdk + opentelemetry-instrumentation-fastapi + opentelemetry-instrumentation-grpc
STACK
Go 1.23 + chi (REST) + google.golang.org/grpc + amqp091-go + Caddy como gateway + OpenTelemetry Go + Jaeger
ESTRUTURA / NOTAS
  • cmd/orders/ — HTTP server chi, middleware de idempotência com Redis
  • cmd/stock/ — gRPC server; proto gerado com protoc + protoc-gen-go
  • cmd/notification/ — consumer AMQP com ack manual e retry com backoff
  • gateway/ — Caddy com Caddyfile: JWT auth via caddy-security, rate_limit plugin
  • Outbox: inserir evento em tabela outbox dentro de transação pgx; goroutine separada publica
  • go.opentelemetry.io/otel + otelchi + otelgrpc para propagação automática de trace
entregável

Repositório com três serviços rodando via docker-compose, README documentando o diagrama de comunicação entre eles (quem chama quem, via qual protocolo), o .proto do serviço de estoque, o schema da tabela de outbox com exemplo de mensagem, e um trace completo no Jaeger mostrando uma requisição de ponta a ponta (gateway → orders → stock via gRPC → notification via fila). Bonus: demonstração de idempotência — mesma requisição enviada duas vezes resulta em um único pedido.

Comunicação entre serviços é território fértil em entrevistas de sistema distribuído e de staff/principal. As perguntas abaixo cobrem os dilemas reais que times enfrentam em produção — não a teoria isolada de cada protocolo.

Q.01

Explique o problema do dual-write em microsserviços e como o outbox pattern o resolve. Quais são as garantias que o outbox oferece e o que ele não garante?

Q.02

Sua API pública recebe um pico de 10× o tráfego normal. Onde rate limiting deve ser aplicado — no gateway, no serviço, ou nos dois? Como você configuraria o algoritmo e os headers de resposta?

Q.03

Você tem um fluxo de pedido que envolve 5 serviços e precisa ser transacional: se o pagamento falhar, o estoque deve ser revertido. Você escolheria saga com orquestração ou coreografia? Por quê?

Q.04

Um cliente reclama que uma requisição está lenta "às vezes". Como você rastrearia essa requisição por 6 microsserviços para identificar onde a latência está sendo introduzida? Quais ferramentas e dados você precisaria?

Q.05

Qual a diferença entre um reverse proxy e um API gateway? Dê um exemplo concreto de responsabilidade que pertence ao gateway e não ao proxy, e vice-versa.