Sursa evenimentului: elemente de bază
Ce este Event Sourcing
Event Sourcing (ES) este o modalitate de stocare a stării obiectelor de domeniu nu ca o „linie curentă”, ci ca un jurnal de evenimente neschimbat care descrie tot ce sa întâmplat. Starea curentă a agregatului este obținută prin rularea (reluarea) evenimentelor sale, iar orice vizualizări citite sunt construite ca proiecții pe partea de sus a acestui jurnal.
Implicații cheie:- Istoria este „sursa principală a adevărului”, starea este proiecția istoriei.
- Orice stat poate fi replicat, verificat și explicat (audit).
- Adăugarea de noi vizualizări și analize nu necesită migrări ale vechilor „instantanee” - este suficient să pierdeți evenimente.
Termeni de bază
Agregate - unitate de domeniu de coerență cu invarianți clari (Comandă, Plată, UserBalance).
Eveniment - un fapt neschimbător care a avut loc în trecut ('plata. autorizat „,” ordin. expediate ").
Event Store este un jurnal apendice care oferă ordinea evenimentelor din cadrul unității.
Versiunea agregată este numărul ultimului eveniment aplicat (pentru concurență optimistă).
Instantaneu - o impresie periodică a stării de a accelera convoluția.
Proiecție (read-model) - vizualizare materializată pentru citire/căutare/raportare (adesea asincronă).
Cum funcționează (fir → evenimente → proiecții)
1. Clientul trimite o comandă ('CapturePayment', 'PlaceOrder').
2. Agregatul validează invarianții și, dacă toate sunt ok, generează evenimente.
3. Evenimentele sunt adăugate atomic în Magazinul de evenimente cu verificarea versiunii (concurență optimistă).
4. Procesoarele de proiecție se abonează la fluxul evenimentului și actualizează modelele de citire.
5. Când agregatul este încărcat pentru următoarea comandă, starea este restabilită la instantaneu (dacă există) → evenimentul după instantaneu.
Designul evenimentului
Atribute necesare (Core)
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" }
}
Recomandări:
- Denumire: 'domeniu. acțiune. v {major} '.
- Aditivitate: câmpurile noi sunt opționale, fără a schimba sensul celor vechi.
- Minimalism: numai fapte, fără duplicarea datelor ușor de recuperat.
Contracte și scheme
Fixați schemele (Avro/JSON Schema/Protobuf) și verificați compatibilitatea pe CI.
Pentru „rupere” modificări - o nouă versiune majoră a evenimentului și publicarea paralelă „v1 ”/„ v2” pentru perioada de migrare.
Acces competitiv: concurență optimistă
Regulă: Evenimente noi pot fi scrise numai dacă "așteptat _ versiune = = current_version'.
Pseudocodul: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
Deci, garantăm integritatea invarianților fără tranzacții distribuite.
Instantanee (accelerație de convoluție)
Faceți un instantaneu la fiecare eveniment sau cronometru N.
Храните 'instantaneu _ stat', 'agregate _ id',' versiune ',' creat _ at '.
Verificați întotdeauna și de a prinde pe evenimente după instantaneu (nu doar încredere în distribuție).
Eliminați instantaneele astfel încât să poată fi recreate din jurnal (nu stocați câmpurile „magice”).
Proiecții și CQRS
ES este combinat în mod natural cu CQRS:- Scrie-model = agregate + Magazin de evenimente.
- Citiți modele = proiecții actualizate de evenimente (carduri Redis, OpenSearch pentru căutare, ClickHouse/OLAP pentru raportare).
- Proiecțiile sunt idempotente: reprocesarea aceluiași 'event _ id' nu modifică rezultatul.
Evoluția și compatibilitatea circuitului
Aditiv-primul: adăugați câmpuri; nu schimba tipurile/semantica.
Pentru schimbări complexe, lansați noi tipuri de evenimente și scrieți migratori de proiecție.
Mențineți o intrare dublă ('v1' + 'v2') pentru perioada de tranziție și trageți 'v1' când toate proiecțiile sunt gata.
Siguranța, PII și „dreptul de a fi uitat”
Istoria conține adesea date sensibile. Abordări:- Minimizați PII în evenimente (identificatori în loc de date, detalii în părți protejate).
- Crypto-erase: criptați câmpurile și, atunci când vi se solicită ștergerea, distrugeți cheia (evenimentul rămâne, dar datele nu sunt disponibile).
- Evenimente de revizuire: 'utilizator. piiredacted. v1 'cu înlocuirea câmpurilor sensibile în proiecții (istoricul păstrează faptul de editare).
- Politici de retenție: pentru unele domenii, unele evenimente pot fi arhivate pentru stocarea WORM.
Performanță și scară
Partiționare: ordinea este importantă în interiorul agregatului - partiție by 'agregate _ id'.
Pornire la rece: instantanee + convoluție periodică de „compactare”.
Apendicele lotului - evenimente de grup într-o singură tranzacție.
Backpressure și DLQ pentru procesoare de proiecție; măsoară decalajul (timpul și numărul de mesaje).
Indexarea magazinului de evenimente: acces rapid prin '(aggregate_type, aggregate_id)' și la timp.
Testarea
Teste de caietul de sarcini pentru agregate - „comenzi → evenimente așteptate” scenariu.
Teste de proiecție: Alimentați fluxul evenimentului și verificați starea/indicii materializați.
Teste de replayability: reconstruiți proiecțiile de la zero pe suport - asigurați-vă că rezultatul se potrivește.
Haos/latență: injectați întârzieri și luați, verificați idempotența.
Exemple de domenii
1) Plăți
Evenimente: 'plata. iniţiat „,” plata. autorizat „,” plata. capturat „,” plata. rambursate ".
Invarianți: nu puteți „captura” fără „autorizat”; sumele sunt non-negative; moneda este neschimbată.
Previziuni: „card de plată” (KV), căutare tranzacție (OpenSearch), raportare (OLAP).
2) Comenzi (e-commerce)
Evenimente: "ordine. plasat „,” comanda. a plătit „,” comanda. Am împachetat, am comandat. expediate „,” comanda. livrate ".
Invarianți: tranziții de stare ale diagramei de stat; anularea este posibilă înainte de „expediat”.
Proiecții: lista comenzilor utilizatorilor, placi SLA după stare.
3) Bilanțuri (Finanțe/iGaming)
Evenimente: "echilibru. depozitat „,” echilibru. debitat „,” sold. creditat „,” echilibru. ajustat ".
Greu invariant: echilibrul nu dispare <0; comenzile sunt 'operation _ id'.
Operațiile critice sunt citite direct din agregat (consistență strictă), UI - din proiecție (eventual).
Structura tipică a magazinului de evenimente (varianta DB)
evenimente
'event _ id (PK)', 'agregate _ type', 'agregate _ id',' version ',' happened _ at ',' event _ type ',' payload ',' meta '
Index: '(aggregate_type, aggregate_id, versiune)'.
instantanee
'agregate _ type', 'agregate _ id',' version ',' state ',' created _ at'
Index: „(aggregate_type, aggregate_id)”.
consumers_offsets
'consumer _ id',' event _ id'/' position ',' update _ at' (pentru proiecții și retail).
Întrebări frecvente (Întrebări frecvente)
Este obligatorie utilizarea ES peste tot?
Nu, nu este. ES este utilă atunci când auditarea, invarianții complexi, reproductibilitatea și diferitele reprezentări ale datelor sunt importante. Pentru CRUD simplu, acest lucru este redundant.
Ce zici de „starea actuală” cereri?
Fie citiți din proiecție (rapid, eventual), fie din unitate (mai scump, dar strict). Operațiunile critice utilizează de obicei a doua cale.
Am nevoie de un broker Kafka/stream?
Magazin de evenimente - sursa adevărului; broker este convenabil pentru distribuirea evenimentelor la proiectoare și sisteme externe.
Ce să faci cu „dreptul de a fi uitat”?
Minimizați PII, criptați câmpurile sensibile și aplicați cripto ștergere/redacție în proiecții.
Cum pot migra date vechi?
Scrieți un script pentru generarea retrospectivă a evenimentelor ("re-highstory") sau începeți cu "state-as-is' și publicați evenimente numai pentru noi modificări.
Antipatterns
Event Sourcing „din obișnuință”: complică sistemul fără beneficii de domeniu.
Evenimente de grăsime: sarcini utile umflate cu PII și duble - frâne și probleme de conformitate.
Lipsa concurenței optimiste: pierderea invarianților la curse.
Proiecții non-reproductibile: fără reluare/instantanee → remedieri manuale.
CDC-uri raw ca evenimente de domeniu: scheme DB scurgeri și conectivitate hard.
Amestecarea evenimentelor interne și de integrare: publicarea unei „vitrine” stabilizate în exterior.
Lista de verificare a producției
- Sunt definite agregate, invariante și evenimente (titluri, versiuni, scheme).
- Event Store oferă ordine în cadrul concurenței agregate și optimiste.
- Instantanee și planul lor de reconstruire sunt incluse.
- Proiecțiile sunt idempotente, există DLQ-uri și valori de lag.
- Schemele sunt validate la CI, politica versiunii este documentată.
- PII este minimizat, câmpurile sunt criptate, există o strategie de „uitare”.
- Proiecție reluare bifată pe bancă; are un plan de recuperare în caz de dezastru.
- Tablouri de bord: viteza aplicației, decalaj de proiecție, erori de aplicare, proporția de retribuții.
Total
Event Sourcing face din istoria sistemului un artefact de primă clasă: captăm fapte, reproducem starea din ele și construim liber orice reprezentări. Acest lucru oferă audit, rezistență la schimbare și flexibilitate de analiză - sub rezerva disciplinei în sisteme, control competitiv și munca competentă cu date sensibile.