Arquitetura de evento
Arquitetura de eventos (EDA)
1) O que é um evento e o porquê do EDA
O evento é um fato imutável que já aconteceu no domínio («PlayerVerified», «PaymentCaptured»). A EDA está construindo uma integração em torno da publicação desses fatos e reações a eles:- a fraca conectividade dos serviços,
- zoom dos consumidores independentemente,
- réplica/reestruturação de projeções,
- uma auditoria transparente.
A EDA não cancela as APIs sincronizadas - ela as complementa, levando as dependências de serviço cruzado para a camada asincrona.
2) Tipos de evento
Domínios: factos de negócios significativos (OrderPlaced, BonusGranted).
Integração: «instantâneos «/alterações para sistemas externos (UserUpdated, WalletBalanceChanged).
Técnico: ciclo de vida e telemetria (Heartbeat, PipelineFailed).
Comandos (não eventos, mas ao lado): Instruções para fazer X (CapturePayment).
Recomendação: Eventos de domínio - primários; a integração é formada por projeções para consumidores específicos.
3) Contratos de eventos e esquema
Схема: Avro/Protobuf/JSON Schema + Schema Registry; estratégia de compatibilidade «BACKWARD» para a evolução dos consumidores, «FULL» em temas críticos.
CloudEvents (id, fonte, tipo, time, subject, datacontenttype) é um título uniforme.
Metadados obrigatórios: 'event _ id' (ULID/UUID), 'accurred _ at', 'producer', 'schema _ versão', 'correlation _ id '/' causation _ id', 'idempotency _ key'.
Versionização: campos add-only, proibição de renomeações/quebras semânticas; novos tipos - novos temas/tipos.
json
{
"type":"record","name":"PaymentCaptured","namespace":"events.v1",
"fields":[
{"name":"event_id","type":"string"},
{"name":"occurred_at","type":{"type":"long","logicalType":"timestamp-micros"}},
{"name":"payment_id","type":"string"},
{"name":"amount","type":{"type":"bytes","logicalType":"decimal","precision":18,"scale":2}},
{"name":"currency","type":"string"},
{"name":"player_id","type":"string"}
]
}
4) Entrega, ordem e coerência
At-least-once como default → precisa de idempotação dos processadores.
Ordem: garantida dentro de uma partição (Kafka) ou de uma fila (RabbitMQ), mas pode ser violada por retalhos; a chave de evento deve refletir o grânulo de domínio da ordem (por exemplo, 'player _ id').
Coerência: para dinheiro/crédito - apenas por meio de revistas/sagas/compensações; evite a LWW.
O modelo de leitura: projeções e cachês podem ser um eventual - exibe «atualização»... e use estratégias RNOT para caminhos rigorosos.
5) Outbox/Inbox и CDC
Outbox: O serviço escreve o fato em seu banco de dados e na tabela de outbox em uma transação → o worker publica no pneu.
Inbox: O consumidor armazena 'event _ id' com o resultado do processo de dedução.
CDC (Mudança Data Capture): fluxo de alterações de BB (binlog/WAL) para o pneu para criar as integrações sem alterações no aplicativo.
Idempotency: processamento por 'idempotency _ key '/' event _ id', não altere o mundo exterior antes da fixação.
6) CQRS и Event Sourcing
CQRS: Compartilhamos o modelo write e projeções read; projeções são construídas a partir de eventos e podem ficar para trás.
Event Surcing: estado do aparelho = aparelhamento de eventos. Benefícios: auditoria completa/réplicas; contras: complexidade de migração/diagramação.
Prática: ES - não em todos os lugares, mas onde a história e as compensações são importantes; CQRS é quase sempre na EDA.
7) Sagas: Orquestra e coreografia
Orquestra: O coordenador envia comandos e aguarda os eventos-respostas; fácil para processos complexos (KYC→Deposit→Bonus).
Coreografia: os serviços respondem aos acontecimentos uns dos outros; mais fácil, mas mais difícil de rastrear.
Defina sempre compensações e deadline de passos.
8) Projeto de topologia (Kafka/RabbitMQ)
Kafka
Top per evento de domínio: 'payments. captured. v1`, `players. verified. v1`.
Chave de partilha: 'player _ id '/' wallet _ id' - onde a ordem é importante.
`replication. factor=3`, `min. insync. replicas = 2 ', projector' acks = all '.
Retenção: por hora (7 a 90 dias) e/ou competition (último estado por chave).
Topics para retry e DLQ com backoff.
RabbitMQ
Exchanges: `topic`/`direct`, routing key `payments. captured. v1`.
Para um fã-out amplo - 'topic' + várias filas; para RPC/comandos - filas individuais.
Quorum Queues para HA; TTL + dead-letter exchange para retrações.
9) Observabilidade e SLO EDA
SLI/SLO:- End-to-end latency (occurred _ at → processado): p50/p95/p99.
- Lag/age: atraso dos consumidores (Kafka consumer lag, Rabbit backlog age).
- Throughput publicação/processamento.
- DLQ-rate e proporção de repetições.
- Êxito de negócios (por exemplo, «depósito confirmado ≤ 5s»).
- Correlação de eventos através de 'trace _ id '/' correlation _ id' (OTel).
- Instâncias (exemplars) a partir de métricas → pista.
- Dashboard «Producer→Broker→Consumer» com alertas burn-rate.
10) Réplicas, retalhos e backfill
Para reestruturar projeções/corrigir bags, acesse a nova projeção/neimspace e altere a leitura.
Exigências legais/empresariais (GDPR/PCI); campos sensíveis - criptografe e/ou toquenie.
Backfill: temas descartáveis/filas, limites nítidos de RPS para não sufocar a proda.
11) Segurança e Complacência
TLS in-transit, mTLS para clientes internos.
Autorização: per-topic/per-exchange LCA; multitenance via namespace/vhost.
PII: Minimizar os campos do evento; envelope metadados separadamente, cargas úteis criptografar se necessário.
Auditoria de acesso a eventos, proibição de todas as chaves poderosas.
Políticas de retenção e permissão de remoção (GDPR): guarde links de dados ou tombstone eventos e remoção em projeções.
12) Testes em EDA
Contract tests: Os consumidores avaliam suas expectativas de padrão (consumer-driven).
Testes replay: uma amostra histórica é testada através de um novo processador/versão do esquema.
Chaos-cenários: atraso/perda do corretor, queda de nós, atraso do consumidor → SLO permanecem dentro.
Smoke em CI: um curto end-to-end pipeline em temas temporais.
13) Migração «integrações CRUD → EDA»
1. Identifique os factos de domínio.
2. Implemente outbox nos serviços de origem.
3. Publicar eventos mínimos de domínio e ligar 1 a 2 projeções.
4. Desabilite gradualmente as integrações sincronizadas por pontos, substituindo-as por subscrições.
5. Digite Schema Registry e sua política de compatibilidade.
6. Amplie os eventos de campo add-only; quebra-quebra - apenas através de novos tipos.
14) Anti-pattern
Eventos = «API DTO» (muito gordurosos, dependentes do modelo interno) - quebram os consumidores.
A ausência de Schema Registry e compatibilidade é uma integração «frágil».
Publicar a partir do código e gravar na base de dados não é atômico (não há outbox) - perde eventos.
«Exactly-once em todos os lugares» - alto preço sem benefício; Melhor at-least-once + idempotidade.
Uma chave de partilha «universal» → uma partição quente.
Uma réplica para a projecção de prod. Quebra o SLO online.
15) Folha de cheque de implementação (0-45 dias)
0-10 dias
Definir eventos de domínio e suas chaves (grânulos de ordem).
Implantar o Schema Registry e aprovar a estratégia de compatibilidade.
Adicionar outbox/inbox a 1-2 serviço; Um CloudEvents-envelope mínimo.
11-25 dias
Digite retry/DLQ, backoff, idempotação dos processadores.
Dashboards: lag/age/end-to-end; burn-rate alert.
Documentação de eventos (diretório), owner's e processos de recuperação de esquemas.
26-45 dias
Réplica/reestruturação da primeira projeção; runbook replay e backfill.
Políticas de segurança (TLS, LCA, PII), retenções, procedimentos GDPR.
Regularmente chaos-e game-days para corretor e consumidores.
16) Métricas de maturidade
100% dos eventos de domínio são descritos por esquemas e registrados.
Outbox/inbox cobre todos os projetores/consórcios Tier-0/1.
SLO: pen95 end-to-end latency e consumer lag dentro dos objetivos ≥ 99%.
As réplicas/Backfill são viáveis sem downthame; há runbook 'i testado.
Versionização: novos campos - sem quebra; Os velhos consumidores não caem.
Segurança: TLS+mTLS, LCA per topic, registros de acesso, Política PII/Retensivo.
17) Mini-snippets
Kafka Producer (publicação confiável, ideias):properties acks=all enable.idempotence=true max.in.flight.requests.per.connection=1 compression.type=zstd linger.ms=5
Processador de consumo (idempotidade, pseudocode):
python if inbox.contains(event_id): return # дедуп process(event) # побочные эффекты детерминированы inbox.commit(event_id) # atomically with side-effect commit_offset()
RabbitMQ Retry via DLX (ideia):
- `queue: tasks` → on nack → DLX `tasks. retry. 1m '(TTL = 60s) → retorno para' tasks '; a seguir, '5m/15m'.
18) Conclusão
A EDA transforma a integração em um fluxo de factos de negócios com contratos claros e coerência gerida. Construa as fundações de esquema + registro, outbox/inbox, chaves de ordem, processadores idumpotentes, SLO e observabilidade, retenções seguras e réplicas. Então os acontecimentos serão a vossa «fonte de verdade» para escalar, analistas e novos fies - sem ligações frágeis ou migrações noturnas.