Arquitetura de referência: orientada a eventos / CQRS
Em uma arquitetura orientada a eventos, os serviços publicam eventos em um log de eventos (ex.: Kafka) em vez de chamarem uns aos outros diretamente, e os consumidores os processam de forma assíncrona. A partir da construção do backbone de eventos, esta árvore percorre passo a passo event sourcing (derivar o estado dos eventos), separação de comandos/consultas com CQRS, projeção do read model, idempotência, tolerância à consistência eventual e a falácia da 'entrega exactly-once'. O objetivo é um sistema fracamente acoplado e escalável, cujos trade-offs de consistência sejam bem compreendidos.
Qual decisão você enfrenta na sua arquitetura orientada a eventos?
A base de um sistema orientado a eventos é um log de eventos durável que conecta os serviços por meio de eventos assíncronos. Você ainda está construindo o backbone, quer derivar o estado dos eventos (event sourcing), ou está separando os caminhos de leitura e gravação (CQRS)?
- Estou construindo o backbone de eventos que conecta os serviços
- Quero derivar o estado do histórico de eventos
- Quero separar os caminhos de leitura e gravação (CQRS)
Como você vai construir o lado da leitura no CQRS, e qual é a sua tolerância de consistência?
No CQRS, os lados de comando (gravação) e de consulta (leitura) são separados; os eventos de gravação atualizam a projeção que alimenta o read model. A questão-chave: você tolera que o read model fique atrás das gravações (consistência eventual), ou espera que cada evento seja processado exatamente uma vez?
- Vou alimentar o read model a partir dos eventos via projeção
- As leituras precisam estar atualizadas; lag é inaceitável
- Quero eventos processados 'exactly once'
Recomendação: um backbone de log de eventos durável
No centro de uma arquitetura orientada a eventos está um log de eventos durável e ordenado, no qual os produtores gravam e que os consumidores leem no próprio ritmo. Esse backbone desacopla os serviços no tempo e na escala.
Recomendação: event sourcing (derivar o estado dos eventos)
No event sourcing, você não armazena o estado atual de uma entidade, mas todos os eventos de alteração (imutáveis) aplicados a ela; o estado atual é derivado aplicando esses eventos em ordem. Oferece um histórico de auditoria completo e a capacidade de voltar a qualquer ponto do passado.
Recomendação: projeção do read model
No CQRS, o lado da gravação produz eventos; uma projeção escuta esses eventos e atualiza um read model otimizado para consultas (view desnormalizada). As leituras são atendidas a partir desse modelo pronto, totalmente separado do caminho de gravação, e os dois lados escalam de forma independente.
Recomendação: projete para tolerar a consistência eventual
Em sistemas orientados a eventos/CQRS, o read model fica levemente atrás das gravações (consistência eventual). Em vez de tentar 'eliminar' isso, projete para tolerá-lo; mantenha separados os poucos fluxos que exigem consistência imediata estrita.
Recomendação: idempotência (a falácia do exactly-once)
Em mensageria distribuída, a 'entrega exactly-once' de ponta a ponta é, na prática, uma falácia; mensagens duplicadas são inevitáveis por causa da rede e das novas tentativas. O objetivo correto é o processamento idempotente: processar o mesmo evento duas vezes deve dar o mesmo resultado que processá-lo uma vez.