Event-Driven Architecture
Como projetar sistemas reativos onde os componentes se comunicam por meio de eventos, alcançando desacoplamento, escalabilidade e processamento assíncrono.
Que problema resolve
Em uma arquitetura tradicional baseada em chamadas síncronas (request-response), os serviços estão fortemente acoplados: o emissor precisa conhecer o receptor, esperar sua resposta e lidar com suas falhas. Isso gera diversos problemas:
- Acoplamento temporal: O emissor fica bloqueado até que o receptor responda
- Acoplamento de conhecimento: O emissor precisa saber quem processa sua solicitação
- Escalabilidade limitada: Adicionar um novo consumidor exige modificar o emissor
- Fragilidade: Se o receptor estiver fora do ar, o emissor também falha
Comunicação síncrona (acoplada):
Order Service ──► Inventory Service (espera resposta)
──► Payment Service (espera resposta)
──► Notification Service (espera resposta)
──► Analytics Service (espera resposta)
Order Service conhece TODOS os serviços
Se um falha, o pedido falha
Adicionar um serviço = modificar Order Service
Como funciona
A arquitetura orientada a eventos (EDA) inverte o modelo de comunicação. Em vez de um serviço chamar diretamente os outros, ele publica um evento que descreve algo que aconteceu. Os serviços interessados se inscrevem nesses eventos e reagem de forma independente.
Comunicação por eventos (desacoplada):
Order Service ──evento──► Event Bus
"OrderCreated"
│
┌───────────┼───────────┐
▼ ▼ ▼
Inventory Payment Notification
Service Service Service
Order Service NÃO conhece os consumidores
Cada serviço reage de forma independente
Adicionar um serviço = se inscrever no evento
Conceitos-chave
| Conceito | Descrição | Exemplo |
|---|---|---|
| Evento | Registro imutável de algo que aconteceu | OrderCreated, PaymentProcessed |
| Produtor | Serviço que publica eventos | Order Service publica OrderCreated |
| Consumidor | Serviço que reage a eventos | Inventory Service escuta OrderCreated |
| Event Bus/Broker | Infraestrutura que transporta eventos | Kafka, RabbitMQ, Amazon SNS/SQS |
| Topic/Queue | Canal por onde os eventos fluem | orders.created, payments.processed |
Tipos de eventos
Domain Events (eventos de domínio): Representam fatos do negócio.
{
"type": "OrderCreated",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"orderId": "ORD-001",
"customerId": "USR-123",
"items": [{"productId": "P001", "quantity": 2}],
"total": 150.00
}
}
Integration Events (eventos de integração): Comunicam mudanças entre bounded contexts.
{
"type": "InventoryReserved",
"source": "inventory-service",
"data": {
"orderId": "ORD-001",
"reservationId": "RES-456",
"status": "confirmed"
}
}
Padrões de entrega
Pub/Sub (Publish-Subscribe): Um evento é entregue a todos os assinantes.
Produtor ──► Topic ──► Consumidor A
──► Consumidor B
──► Consumidor C
Event Streaming: Os eventos são armazenados em um log persistente e os consumidores leem no seu próprio ritmo.
Produtor ──► Log persistente (Kafka)
[evento1, evento2, evento3, ...]
Consumidor A: lendo o evento 3 (em dia)
Consumidor B: lendo o evento 1 (atrasado, processando)
Consumidor C: novo, começa a partir do evento 1
Garantias de entrega
| Garantia | Descrição | Uso |
|---|---|---|
| At-most-once | O evento é entregue no máximo uma vez (pode se perder) | Métricas, analytics |
| At-least-once | O evento é entregue pelo menos uma vez (pode se duplicar) | A maioria dos casos (com idempotência) |
| Exactly-once | O evento é entregue exatamente uma vez | Transações financeiras (difícil de alcançar) |
Vantagens
- Desacoplamento: Produtores e consumidores não se conhecem
- Escalabilidade: Adicionar consumidores não exige modificar produtores
- Resiliência: Se um consumidor está fora do ar, os eventos se acumulam e são processados quando ele voltar
- Processamento assíncrono: O produtor não espera os consumidores terminarem
- Auditoria natural: Os eventos formam um log de tudo o que aconteceu no sistema
- Extensibilidade: Novas funcionalidades são adicionadas se inscrevendo em eventos existentes
Trade-offs / Desvantagens
- Consistência eventual: Os dados não são atualizados instantaneamente em todos os serviços
- Complexidade de debugging: Rastrear o fluxo de um evento através de múltiplos serviços é difícil
- Ordenação: Garantir a ordem de processamento dos eventos exige um projeto cuidadoso
- Duplicatas: Os consumidores precisam ser idempotentes para lidar com eventos duplicados
- Infraestrutura adicional: Você precisa de um broker de mensageria (Kafka, RabbitMQ) com sua operação
- Testing complexo: Testar fluxos assíncronos é mais difícil do que testar chamadas síncronas
Quando usar
- Sistemas onde múltiplos serviços precisam reagir ao mesmo evento
- Quando o processamento pode ser assíncrono (você não precisa de resposta imediata)
- Sistemas com requisitos de alta escalabilidade e throughput
- Quando você precisa desacoplar serviços para que evoluam de forma independente
- Fluxos de negócio complexos com múltiplas etapas (pedidos, pagamentos, envios)
- Quando você precisa de um log de auditoria de tudo o que acontece no sistema
Quando evitar
- Operações que exigem resposta síncrona imediata (consultas do usuário)
- Sistemas simples com poucos serviços e fluxos lineares
- Quando a consistência forte é um requisito não negociável
- Times sem experiência em sistemas distribuídos e debugging assíncrono
- Quando você não consegue justificar a infraestrutura de um broker de mensageria
Tecnologias e implementações comuns
| Categoria | Opções |
|---|---|
| Event Streaming | Apache Kafka, Amazon Kinesis, Azure Event Hubs |
| Message Brokers | RabbitMQ, Amazon SQS/SNS, Google Pub/Sub, NATS |
| Event Store | EventStoreDB, Kafka (como event store) |
| Frameworks | Spring Cloud Stream, MassTransit (.NET), Axon Framework |
| Observabilidade | OpenTelemetry, Jaeger, Zipkin (tracing distribuído) |
Relação com outros padrões
- Saga Pattern: Usa eventos para coordenar transações distribuídas entre serviços
- Outbox Pattern: Garante a publicação confiável de eventos junto com mudanças no banco de dados
- CQRS: Separa leituras e escritas usando eventos para sincronizar os modelos
- Idempotência: Os consumidores precisam ser idempotentes para lidar com eventos duplicados
- Circuit Breaker: Protege os consumidores de sobrecarga quando há picos de eventos
Próximos passos
A arquitetura orientada a eventos é a base da comunicação nos microsserviços modernos. Para proteger a integração com sistemas externos que não falam a sua linguagem de eventos, explore o Anti-Corruption Layer. Para garantir que os consumidores lidem corretamente com duplicatas, revise o padrão de Idempotência.