Event Source - Basi
Cos'è Event Source
Event Source (ES) è un modo per memorizzare lo stato degli oggetti di dominio non come una stringa corrente, ma come un registro eventi immutabile che descrive tutto ciò che è accaduto. Lo stato corrente dell'aggregazione è rappresentato da una combinazione degli eventi e le viste di lettura vengono create come proiezioni sopra il registro.
Indagini chiave:- La storia è la fonte primaria della verità, la condizione è la proiezione della storia.
- Qualsiasi stato può essere riprodotto, convalidato e spiegato.
- L'aggiunta di nuove viste e analisi non richiede la migrazione di vecchie snapshot - basta perdere eventi.
Termini di base
L'aggregazione è un'unità di dominio con invarianti chiari (Order, Payment, UserBalance).
L'evento è un fatto non modificabile avvenuto in passato ('payment. authorized`, `order. shipped`).
Event Store è un registro di append che garantisce l'ordine degli eventi all'interno dell'unità.
La versione dell'unità è il numero dell'ultimo evento applicato (per ottimistico concertency).
Snapshot è un calco di stato periodico per accelerare la coagulazione.
Proiezione (modello read) - Vista materializzata per la lettura, la ricerca e il reporting (spesso asincrona).
Come funziona (flusso di comandi di eventi di proiezione )
1. Il cliente sta inviando una squadra.
2. L'aggregazione valuta gli invarianti e, se tutto va bene, genera eventi.
3. Gli eventi vengono aggiunti atomonicamente all'Event Store con la versione ottimistica.
4. I processori di proiezione sono iscritti al flusso di eventi e aggiornano i modelli read.
5. Durante il caricamento dell'aggregazione per il comando seguente, lo stato viene ripristinato (se disponibile) dopo il snap dell'evento.
Progettazione degli eventi
Attributi obbligatori (kernel)
json
{
"event_id": "uuid",
"event_type": "payment. authorized. v1",
"aggregate_type": "Payment",
"aggregate_id": "pay_123",
"aggregate_version": 5,
"occurred_at": "2025-10-31T10:42:03Z",
"payload": { "amount": 1000, "currency": "EUR", "method": "card" },
"meta": { "trace_id": "t-abc", "actor": "user_42" }
}
Raccomandazioni:
- La denominazione è «domain». action. v{major}`.
- Additività: i nuovi campi sono opzionali, senza modificare il significato dei vecchi campi.
- Minimalismo: solo fatti, senza duplicazioni di dati facilmente recuperabili.
Contratti e schemi
Fissare gli schemi (Avro/JSON Schema/Protobuf) e verificare la compatibilità con CI.
Per le modifiche "frammentarie", la nuova versione maggiore dell'evento e la pubblicazione parallela dì v1 "/" v2 "per il periodo di migrazione.
Accesso competitivo: ottimistica concurrency
Regola: è possibile scrivere nuovi eventi solo se 'expected _ variante = = current _ variante'.
Pseudocode:pseudo load: snapshot(state, version), then apply events > version new_events = aggregate. handle(command)
append_to_store(aggregate_id, expected_version=current_version, events=new_events)
//if someone has already written an event between load and append, the operation is rejected -> retray with reload
In questo modo garantiamo l'integrità degli invarianti senza transazioni distribuite.
Snapshot (accelerazione della saldatura)
Fate un snap ogni n eventi o timer.
Храните `snapshot_state`, `aggregate_id`, `version`, `created_at`.
Controlla sempre e raggiungi gli eventi dopo il snapshot (non fidarti solo del calco).
Togliere i nastri in modo che possano essere ripiegati dal cavo (non memorizzare i campi magici).
Proiezioni e CQRS
ES si combina naturalmente con CQRS:- Modello Write = unità + Event Store.
- Modelli read = proiezioni aggiornate da eventi (Redis schede, ricerca, per report).
- Le proiezioni sono idipotenti: la riprogettazione dello stesso «event _ id» non cambia il risultato.
Evoluzione degli schemi e compatibilità
Additive-first - Aggiungere campi; Non cambiare i tipi/semantiche.
Per le modifiche complesse, rilasciare nuovi tipi di eventi e scrivere i migratori di proiezione.
Mantenere la doppia scrittura ('v1' + 'v2') per il periodo di transizione e filmare 'v1' quando tutte le proiezioni sono pronte.
Sicurezza, PII e diritto all'oblio
La storia contiene spesso dati sensibili. Approcci:- Ridurre al minimo il PII negli eventi (ID anziché dati, parti in lati protetti).
- Crittografia - Cifrare i campi e eliminare la chiave quando si chiede l'eliminazione (l'evento rimane ma i dati non sono disponibili).
- Eventi di redazione: 'user. piiredacted. v1 'sostituito da campi sensibili nelle proiezioni (cronologia conserva la modifica).
- Criteri di rettificazione: per alcuni domini è possibile archiviare alcuni eventi nello storage WORM.
Prestazioni e scalabilità
Partizionamento: l'ordine è importante all'interno dell'unità - Partizionare per «aggregate _ id».
Partenza fredda: snapshot + compressione periodica.
Appended batch: raggruppa gli eventi con una singola transazione.
Backpressure e DLQ per i processori di proiezione misurare la lega (tempo e numero di messaggi).
Indice Event Store: accesso rapido per '(aggregate _ type, aggregate _ id)' e in base all'ora.
Test
Specification test per aggregati: script «comandi per gli eventi previsti».
Progection test: inserisci il flusso di eventi e controlla lo stato/gli indici materializzati.
Replayability test - Riarrangiare le proiezioni da zero nello stand. Assicurarsi che il risultato corrisponda.
Chaos/latency: inserisci ritardi e prese, controlla l'idempotenza.
Esempi di dominio
1) Pagamenti
Eventi dì payment ". initiated`, `payment. authorized`, `payment. captured`, `payment. refunded`.
Invarianti: non è possibile «capture» senza «authorized»; gli importi non sono costosi; la valuta è invariata.
Proiezioni: carta di pagamento (KV), ricerca transazioni (OpenSearch), report (OLAP).
2) Ordini (e-commerce)
Eventi: 'order. placed`, `order. paid`, `order. packed`, `order. shipped`, `order. delivered`.
Invarianti - Transizioni di stato in un grafico di stato può essere annullato fino a «shipped».
Proiezioni: elenco degli ordini dell'utente, SLA-dashboard per stato.
3) Bilanci (finanza/iGaming)
Eventi dì equilibrio. deposited`, `balance. debited`, `balance. credited`, `balance. adjusted`.
Invariante rigido: il bilanciamento non parte. <0 i comandi sono idonei a «operation _ id».
Le operazioni critiche vengono lette direttamente dall'aggregazione (coerenza rigorosa) e dall'UI dalla proiezione (avvenual).
Struttura standard Event Store (opzione database)
events
`event_id (PK)`, `aggregate_type`, `aggregate_id`, `version`, `occurred_at`, `event_type`, `payload`, `meta`
Indice: '(aggregate _ type, aggregate _ id, variante)'.
snapshots
`aggregate_type`, `aggregate_id`, `version`, `state`, `created_at`
Indice: '(aggregate _ type, aggregate _ id)'.
consumers_offsets
«consumer _ id», «event _ id »/« position», «updated _ at» (per proiezioni e retlay).
Domande frequenti (FAQ)
È necessario utilizzare ES ovunque?
No, no. ES è utile quando le verifiche, gli invarianti complessi, la riproduzione e le viste dei dati sono importanti. Per un CRUD semplice è eccessivo.
Come vanno le richieste di «stato attuale»?
O leggi dalla proiezione (veloce, avvenual) o dall'aggregazione (più costosa, ma rigorosa). Le operazioni critiche di solito utilizzano un secondo percorso.
Ha bisogno di Kafka/stream broker?
Event Store è la fonte della verità; il broker è facile da distribuire ai proiettori e ai sistemi esterni.
E il «diritto all'oblio»?
Minimizza il PII, crittografa i campi sensibili e applica la crittografia/revisione nelle proiezioni.
Come migrare i vecchi dati?
Scrivete uno script per generare eventi retrospettivi (re-highstory) o iniziate con lo stato-come-è e pubblicate eventi solo per nuove modifiche.
Antipattern
Event Source «abitudine»: rende il sistema più difficile senza vantaggi di dominio.
Fat events: payload gonfiati con PII e doppie - freni e problemi di compilazione.
Assenza di concurrency ottimistico: perdita di invarianti durante le corse.
Proiezioni impermeabili: nessuna replica/snapshot, fissaggio manuale.
CDC crudi come eventi di dominio: perdita di schemi di database e connettività rigida.
Miscelazione degli eventi interni e di integrazione: pubblicare una vetrina stabilizzata all'esterno.
Foglio di assegno per la produzione
- Sono stati definiti aggregati, invarianti ed eventi (nomi, versioni, schemi).
- Event Store fornisce l'ordine all'interno dell'unità e ottimistico concertency.
- Sono inclusi i snapshot e il piano di rielaborazione.
- Le proiezioni sono idipotenti, ci sono DLQ e metriche della laga.
- Gli schemi sono validi su CI, il criterio di versione è documentato.
- PII è stato minimizzato, i campi sono cifrati, c'è una strategia di dimenticanza.
- Le repliche delle proiezioni sono state verificate nello stand; C'è un piano di disaster recovery.
- Dashboard: velocità dell'appendice, gioco di proiezioni, errori di applicazione, quota di retrai.
Totale
Event Sorcing rende la storia del sistema un artefatto di prima classe, che cattura i fatti, riproduce lo stato e costruisce liberamente qualsiasi rappresentazione. Ciò consente di verificare, gestire i cambiamenti e la flessibilità degli analisti, con disciplina dei circuiti, controllo competitivo e gestione dei dati sensibili.