Event Sourcing: podstawy
Co to jest Event Sourcing
Event Sourcing (ES) to sposób przechowywania stanu obiektów domeny nie jako „bieżącej linii”, ale jako niezmiennego dziennika zdarzeń opisującego wszystko, co się stało. Aktualny stan agregatu uzyskuje się poprzez skasowanie (powtórzenie) jego zdarzeń, a wszelkie odczytane widoki są budowane jako projekcje na górze tego dziennika.
Najważniejsze konsekwencje:- Historia jest „podstawowym źródłem prawdy”, stan jest projekcją historii.
- Każde państwo może zostać powtórzone, sprawdzone i wyjaśnione (audyt).
- Dodawanie nowych poglądów i analiz nie wymaga migracji starych „migawek” - wystarczy stracić wydarzenia.
Podstawowe terminy
Agregat - jednostka dziedziny spójności z wyraźnymi niezmiennikami (zlecenie, płatność, saldo).
Zdarzenie - niezmienny fakt, który miał miejsce w przeszłości ("płatność. autoryzowany „,” order. wysłane ").
Event Store to dziennik tylko z dodatkiem, który zapewnia kolejność zdarzeń w jednostce.
Wersja zagregowana jest liczbą ostatniego zdarzenia zastosowanego (dla optymistycznego współistnienia).
Migawka - okresowe wrażenie stanu przyspieszenia konwolekcji.
Projekcja (model odczytu) - zmaterializowany widok do odczytu/wyszukiwania/raportowania (często asynchroniczny).
Jak to działa (wątek → wydarzenia → projekcje)
1. Klient wysyła polecenie ('CapturePayment', 'KeyOrder').
2. Agregat zwaliduje niezmienne i, jeśli wszystkie są w porządku, generuje zdarzenia.
3. Zdarzenia są atomowo dodawane do Sklepu Zdarzeń z weryfikacją wersji (optymistyczna współzależność).
4. Procesory projekcji zapisują się do przepływu zdarzeń i aktualizują modele odczytu.
5. Po załadowaniu agregatu dla następującego polecenia, status zostanie przywrócony do migawki (jeśli występuje) → zdarzenie po migawce.
Projekt imprezy
Wymagane atrybuty (rdzeń)
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" }
}
Zalecenia:
- Nazwa: 'domena. działania. v {major} '.
- Dodatkowość: nowe pola są opcjonalne, bez zmiany znaczenia starych.
- Minimalizm: tylko fakty, bez powielania łatwo odzyskiwalnych danych.
Umowy i programy
Naprawić schematy (Avro/JSON Schema/Protobuf) i sprawdzić zgodność na CI.
Dla zmian „łamiących” - nowa główna wersja wydarzenia i równoległa publikacja 'v1 '/' v2' dla okresu migracji.
Konkurencyjny dostęp: optymistyczne współistnienie
Reguła: Nowe zdarzenia mogą być zapisywane tylko wtedy, gdy 'expected _ version = = current_version'.
Pseudokoda: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
Gwarantujemy integralność niezmienników bez transakcji rozproszonych.
Migawki (przyspieszenie konwoluracyjne)
Zrób migawkę każdego zdarzenia N lub timer.
Мранита 'snapshot _ state', 'aggregate _ id',' version ',' created _ at '.
Zawsze sprawdzaj i nadrabiaj zaległości po migawce (nie ufaj tylko obsadzie).
Usuń migawki, aby można je było odtworzyć z dziennika (nie przechowywać pól „magicznych”).
Projekcje i CQRS
ES jest naturalnie połączony z CQRS:- Write-model = agregaty + Event Store.
- Czytaj modele = projekcje zaktualizowane przez zdarzenia (karty Redis, OpenSearch dla wyszukiwania, ClickHouse/OLAP dla raportowania).
- Projekcje są idempotentne: ponowne przetwarzanie tego samego 'event _ id' nie zmienia wyniku.
Ewolucja i kompatybilność obwodów
Dodatek pierwszy: dodać pola; nie zmieniać typów/semantyki.
W przypadku złożonych zmian, zwolnij nowe typy zdarzeń i napisz migratory projekcji.
Utrzymać podwójny wpis ('v1' + 'v2') dla okresu przejściowego i strzelać 'v1', gdy wszystkie projekcje są gotowe.
Bezpieczeństwo, PII i „prawo do bycia zapomnianym”
Historia często zawiera dane wrażliwe. Podejścia:- Zminimalizuj PII w zdarzeniach (identyfikatory zamiast danych, szczegóły w chronionych stronach).
- Crypto-erase: szyfruj pola i, po wyświetleniu zapytania o usunięcie, zniszcz klucz (zdarzenie pozostaje, ale dane nie są dostępne).
- Zdarzenia rewizji: 'użytkownik. piryredacted. v1 "z wymianą pól wrażliwych w projekcjach (historia zachowuje fakt edycji).
- Zasady zachowania: dla niektórych domen niektóre zdarzenia można archiwizować do magazynu WORM.
Wydajność i skala
Podział: kolejność jest ważna wewnątrz kruszywa - partycja przez 'agregate _ id'.
Zimny start: migawki + okresowe „zagęszczanie” konwolution.
Dodatek partii - zdarzenia grupowe w jednej transakcji.
Backpressure i DLQ dla procesorów projekcyjnych; pomiar lag (czas i liczba wiadomości).
Indeksowanie Event Store: szybki dostęp przez '(aggregate_type, aggregate_id)' i przez czas.
Testowanie
Testy specyfikacji agregatów - scenariusz „commands → expected events”.
Testy projekcyjne: Nakarm przepływ zdarzenia i sprawdź zmaterializowany stan/indeksy.
Powtórność testów: odbudować projekcje od podstaw na stoisku - upewnij się, że wynik pasuje.
Chaos/opóźnienie: wstrzyknąć opóźnienia i pobiera, sprawdzić idempotencję.
Przykłady domen
1) Płatności
Zdarzenia: "płatność. zainicjowana płatność „,”. autoryzowana płatność „,”. przechwycona płatność „,”. zwrócone ".
Niezmienne: nie można „uchwycić” bez „autoryzowanego”; kwoty nie są ujemne; waluta jest niezmieniona.
Projekcje: „karta płatnicza” (KV), wyszukiwanie transakcji (OpenSearch), raportowanie (OLAP).
2) Zamówienia (handel elektroniczny)
Wydarzenia: "kolejność. umieszczone „,” zamówienie. zapłacone „,” order. zapakowane „,” zamówienie. wysłane „,” zamówienie. dostarczone ".
Niezmienne: przejścia na mapę stanu; anulowanie jest możliwe przed wysłaniem.
Projekcje: lista zamówień użytkowników, tablice SLA według statusu.
3) Bilans (finanse/iGaming)
Wydarzenia: "równowaga. złożone „,” saldo. obciążone „,” równowaga. zapisane „,” saldo. dostosowane ".
Twardy niezmienny: równowaga nie ustępuje <0; polecenia są 'operation _ id'.
Operacje krytyczne odczytywane są bezpośrednio z agregatu (ścisła spójność), interfejsu użytkownika - z projekcji (ewentualnie).
Typowa struktura sklepu zdarzeń (wariant DB)
zdarzenia
„event _ id (PK)”, „aggregate _ type”, „aggregate _ id”, „version”, „occurred _ at”, „event _ type”, „payload”, „meta”
Indeks: '(aggregate_type, aggregate_id, wersja)'.
migawki
"aggregate _ type", "aggregate _ id'," version "," state "," created _ at "
Wskaźnik: „(aggregate_type, aggregate_id)”.
consumers_offsets
„consumer _ id',” event _ id'/„ position ”,„ updated _ at ”(dla projekcji i detalicznych).
Często zadawane pytania (często zadawane pytania)
Czy wszędzie obowiązkowe jest stosowanie ES?
Nie, nie jest. ES jest przydatny w przypadku audytu, złożonych niezmienników, odtwarzalności i różnych reprezentacji danych. Dla prostego CRUD jest to zbędne.
A co z prośbami „aktualnego stanu”?
Albo odczytać z projekcji (szybko, ewentualnie), albo z jednostki (droższe, ale ściśle). Operacje krytyczne zwykle używają drugiej ścieżki.
Czy potrzebuję brokera Kafka/stream?
Event Store - źródło prawdy; broker jest wygodny do dystrybucji wydarzeń do projektorów i systemów zewnętrznych.
Co zrobić z „prawem do bycia zapomnianym”?
Zminimalizuj PII, szyfruj pola wrażliwe i w projekcjach zastosuj wymazanie/redakcję krypto.
Jak migrować stare dane?
Napisz skrypt do generowania zdarzeń retrospektywnych („re-highstory”) lub zacznij od „state-as-is” i publikuj wydarzenia tylko dla nowych zmian.
Antypattery
Event Sourcing „out of habit”: komplikuje system bez korzyści domeny.
Wydarzenia tłuszczowe: wzdęte ładunki z PII i dwukrotnie - hamulce i problemy z przestrzeganiem.
Brak optymistycznej jednoczesności: utrata niezmienników podczas wyścigów.
Nie powtarzalne projekcje: brak powtórki/migawki → ręczne poprawki.
Surowe CDC jako zdarzenia domeny: wyciekły schematy DB i twarda łączność.
Mieszanie imprez wewnętrznych i integracyjnych: opublikować stabilizowaną „prezentację” na zewnątrz.
Lista kontrolna produkcji
- Zdefiniowano agregaty, niezmienne i zdarzenia (tytuły, wersje, schematy).
- Event Store zapewnia zamówienie w ramach agregatu i optymistycznej jednoczesności.
- Zalicza się migawki i ich plan odbudowy.
- Projekcje są idempotentne, istnieją DLQ i mierniki opóźnień.
- Programy są zatwierdzane w CI, polityka wersji jest udokumentowana.
- PII jest zminimalizowany, pola są szyfrowane, istnieje strategia „zapominania”.
- Powtórka projekcji sprawdzona na ławce; ma plan naprawy klęsk żywiołowych.
- Deski rozdzielcze: prędkość aplikacji, opóźnienie projekcji, błędy aplikacji, odsetek retras.
Razem
Event Sourcing sprawia, że historia systemu jest artefaktem pierwszej klasy: rejestrujemy fakty, odtwarzamy z nich stan i swobodnie budujemy wszelkie reprezentacje. Daje to audyt, odporność na zmiany i elastyczność analityki - z zastrzeżeniem dyscypliny w programach, kontroli konkurencyjnej i kompetentnej pracy z danymi wrażliwymi.