Event Sourcing: Հիմքեր
Ի՞ նչ է Event Sourcing-ը
Event Sourcing-ը (ES) հիբրիդային օբյեկտների վիճակը պահելու միջոց է ոչ թե «ներկա տողի» տեսքով, այլ որպես իրադարձությունների անփոփոխ ամսագիր, որը նկարագրում է այն ամենը, ինչ տեղի ունեցավ։ Ագրեգատի ներկա վիճակը ստացվում է նրա իրադարձությունների մի փաթեթ (replay), իսկ կարդալու համար ցանկացած ներկայացում կառուցվում է որպես կանխատեսումներ այս ամսագրի վերևում։
Հիմնական սկզբունքները
Պատմությունը «ճշմարտության առաջնային աղբյուրն է», վիճակը պատմության պրոյեկտն է։
Ցանկացած վիճակ կարող է վերարտադրվել, ստուգել և բացատրել (աուդիտ)։
Նոր ներկայացումների ավելացումը և վերլուծաբանները չեն պահանջում հին «նկարներ», բավական է կորցնել իրադարձությունները։
Հիմնական տերմինները
Ագրեգատը էքսպորտային միավորն է, որն ունի հստակ ինվարանտներ (Order, Payment, UserBalts)։
Իրադարձությունը անփոփոխ փաստ է, որը տեղի ունեցավ անցյալում («payment»)։ authorized`, `order. shipped`).
Event Store-ը append-onley ամսագիրն է, որն ապահովում է իրադարձությունների կարգը ագրեգատի սահմաններում։
Ագրեգատի տարբերակը վերջին օգտագործված իրադարձության թիվ է (optimistic concurrency)։
Կեղտաջրերը պետության պարբերական կույր են, որպեսզի արագացնեն այն։
Պրոյեկցիան (read-մոդել) նյութականացված տեսք է կարդալու/որոնելու/հաշվետվության համար (հաճախ ասինխրոն)։
Ինչպե՞ ս է այն աշխատում (թիմերի հոսքը ռուսական պրոյեկտների իրադարձություններին)
1. Հաճախորդը ուղարկում է թիմը («Captom Payment», «Plant Order»)։
2. Ագրեգատը առաջնորդում է ինվարանտները, և եթե ամեն ինչ տեղի է ունենում, տեղի է ունենում։
3. Ատոմային իրադարձությունները ավելացվում են Event Store-ում տարբերակի ստուգմամբ (optimistic concurrency)։
4. Պրոյեկտների իրականացումը ստորագրվել է իրադարձությունների հոսքի վրա և թարմացնում է read մոդելները։
5. Հաջորդ թիմի համար ագրեգատը բեռնելիս վիճակը վերականգնվում է 'դիպուկահարները (եթե կա) ռուսական իրադարձություններ են դիպուկից հետո։
Իրադարձությունների դիզայն
Պարտադիր ատրիբուտներ (միջուկ)
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" }
}
Առաջարկություններ
Անունը '"domain. action. v{major}`.
Addimation 'նոր դաշտերը օբյեկտիվ են, առանց հին իմաստի փոփոխության։
Մինիմալիզմ 'միայն փաստերը, առանց հեշտությամբ վերականգնվող տվյալների։
Պայմանագրեր և սխեմաներ
Գրանցեք սխեմաները (Avro/JSON Schema/Delobuf) և ստուգեք CI-ի համատեղելիությունը։
«Կոտրող» փոփոխությունների համար իրադարձության նոր մաժոր տարբերակն է և զուգահեռ հրատարակումը '«v1 »/« v2» ժամանակահատվածի համար։
Մրցակցային հասանելիություն 'optimistic concurrency
Նոր իրադարձությունների ձայնագրումը հնարավոր է միայն եթե «expected _ version = = = current _ version»։
Prindocod
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
Այսպիսով, մենք երաշխավորում ենք ինվարանտների ամբողջականությունը առանց բաշխված գործարքների։
Դիպուկահարներ (արագացում)
Վերցրեք յուրաքանչյուր N իրադարձության կափարիչը կամ թայմերը։
Храните `snapshot_state`, `aggregate_id`, `version`, `created_at`.
Միշտ ստուգեք և վերցրեք իրադարձությունները կեղևից հետո (մի վստահեք միայն կույր)։
Վերցրեք կեղտաջրերը այնպես, որ դրանք կարողանան վերազինել հատակից (մի պահեք «կախարդական» դաշտերը)։
Պրոյեկտներ և CQRS
ES-ը բնականաբար զուգորդվում է CQRS-ի հետ
Write-մոդելը = միավորներ + Event Store։
Read-մոդելներ = պրոյեկտներ, որոնք թարմացվում են իրադարձություններով (Redis քարտ, OpenSearch, որոնման համար, ClickHouse/OLAP մրցույթի համար)։
Idempotent պրոյեկտները 'նույն «event _ id» -ի վերարտադրումը չի փոխում արդյունքը։
Սխեմաների էվոլյուցիան և համատեղելիությունը
Delitive-first 'ավելացրեք դաշտերը։ մի փոխեք տեսակները/սեմանտիկան։
Բարդ փոփոխությունների համար 'նոր տեսակի իրադարձություններ արտադրեք և գրեք պրոյեկտորների բաղադրիչներ։
Աջակցեք կրկնակի ձայնագրությանը («v1 '+' v2») անցումային ժամանակահատվածում և նկարահանեք «v1», երբ բոլոր պրոյեկտները պատրաստ են։
Անվտանգություն, PII և «մոռացման իրավունք»
Պատմությունը հաճախ պարունակում է զգայուն տվյալներ։ Մոտեցումներ
Microsoft PII-ը իրադարձությունների մեջ (ցուցիչներ տվյալների փոխարեն, մանրամասները պաշտպանված կողմերում)։
Ծպտյալ լվացք 'ծածկագրեք դաշտերը և պահանջեք, որ լուծեք բանալին (իրադարձությունը մնում է, բայց տվյալները անհասանելի են)։
Իրադարձություններ-2019: 'user. piiredacted. v1 '' զգայուն դաշտերը պրոյեկտներում փոխարինելով (պատմությունը պահպանում է խմբագրման փաստը)։
Ռեթենացիայի քաղաքականությունները. Որոշ ֆորումների համար իրադարձությունների մի մասը կարելի է արխիվացնել WORM-2019-ում։
Արտադրողականություն և մեծացում
Կուսակցությունը 'կարգը կարևոր է ագրեգատի ներսում' նվագակցեք «aggregate _ id»։
Սառը սկիզբը 'կեղտաջրերը + պարբերական «բազմապատկող»։
Batch Append 'խմբավորել իրադարձությունները մեկ գործարքով։
Backpressure և DLQ պրոյեկտների համար։ չափեք լամպը (ժամանակը և հաղորդագրությունների քանակը)։
Event Store ինդեքսավորումը 'արագ մուտք' (aggregate _ type, aggregate _ id) և ժամանակի ընթացքում։
Թեստավորում
Speciforment tes.ru-ը ագրեգատների համար '«թիմերը կանխատեսելի իրադարձություններ են» սցենարը։
Projw.tes.ru: Դարձրեք իրադարձությունների հոսքը և հաստատեք նյութականացված վիճակը/ինդեքսները։
Replayability tes.ru-ը 'հատեք «զրոյի» պրոյեկտները պատին, համոզվեք, որ արդյունքը համընկնում է։
Chaos/latency: Ներարկեք հետաձգումներ և կրկնապատկումներ, ստուգեք կուռքերը։
Օրինակների օրինակներ
1) Վճարումներ
Իրադարձությունները '<pay.ru։ initiated`, `payment. authorized`, `payment. captured`, `payment. refunded`.
Invariants: Դուք չեք կարող «capture» առանց «authorized»; գումարը ոչ բացասական է. արժույթը անփոփոխ է։
Պրոյեկտներ ՝ «մրցույթի քարտը» (KV), գործարքների որոնումը (OpenSearch), հաշվետվությունները (OLAP)։
2) Պատվերներ (e-commerce)
Իրադարձությունները 'order. placed`, `order. paid`, `order. packed`, `order. shipped`, `order. delivered`.
Invariants 'պետական դիագրամում ստատուսների անցում; վերացումը հնարավոր է մինչև «shipped»։
Պրոյեկտներ 'օգտագործողի պատվերների ցանկը, SLA-dashbords կարգավիճակների վրա։
3) Հավասարակշռություններ (ֆինանսներ/iGaming)
Իրադարձությունները '"bal.ru. deposited`, `balance. debited`, `balance. credited`, `balance. adjusted`.
Կոշտ ինվարանտը 'հավասարակշռությունը չի հեռանում <0; հրամաններ են «operation _ id»։
Կրիտիկական վիրահատությունները կարդում են հենց ագրեգատից (խիստ համաձայնություն), UI-ից 'պրոյեկտից (eventae)։
Event Store-ի տիպային կառուցվածքը (տարբերակը BD-ից)
events
`event_id (PK)`, `aggregate_type`, `aggregate_id`, `version`, `occurred_at`, `event_type`, `payload`, `meta`
Ինդեքսը ՝ «(aggregate _ type, aggregate _ id, version)»։
snapshots
`aggregate_type`, `aggregate_id`, `version`, `state`, `created_at`
Ինդեքսը ՝ «(aggregate _ type, aggregate _ id)»։
consumers_offsets
«consumer _ id», «event _ id »/« pos.ru», «contated _ at» (պրոյեկցիաների և ռետրլեյի համար)։
Հաճախակի հարցեր (FAQ)
Արդյո՞ ք պետք է օգտագործել ES-ը ամենուր։
Ոչ։ ES-ը օգտակար է, երբ կարևոր են աուդիտը, բարդ ինվարիատները, վերարտադրողականությունը և տվյալների տարբեր ներկայացումները։ Պարզ CRUD-ի համար դա չափազանց մեծ է։
Ինչպե՞ ս լինել «իրական վիճակի» պահանջների հետ։
Կամ պատրաստված է պրոյեկցիայից (արագ, eventae) կամ ագրեգատից (ավելի թանկ, բայց խիստ)։ Կրիտիկական վիրահատությունները սովորաբար օգտագործում են երկրորդ ճանապարհը։
Արդյո՞ ք Kafka/strem-brocker-ը կարիք ունի։
Event Store-ը ճշմարտության աղբյուրն է։ բրոքերը հարմար է իրադարձությունների տարածման համար պրոյեկտորների և արտաքին համակարգերի համար։
Ի՞ նչ անել «մոռացության իրավունքի» հետ։
Նվազագույնի հասցնել PII-ը, ծածկել զգայուն դաշտերը և օգտագործել ծպտյալ լվացում/խմբագրություն նախագծերում։
Ինչպե՞ ս հին տվյալները գաղթել։
Գրեք հետադարձ կապ ունեցող իրադարձությունների մասին («re-hestori») կամ սկսեք «վիճակից» և հրապարակեք իրադարձությունները միայն նոր փոփոխությունների համար։
Antipatterny
Event Sourcing-ը «սովորությամբ» բարդացնում է համակարգը առանց հիբրիդային օգուտների։
Fat events: բաժանված payload 'a PII-ի և դուբլների հետ' արգելակներ և կոմպլանսի խնդիրներ։
Optimistic concurrency-ի բացակայությունը 'ինվարանտների կորցումը մրցավազքում։
Ոչ ոգեշնչող պրոյեկտներ. Ոչ մի ռեփլե/դիպուկահարներ չկան։
Հում CDC-ն որպես հիբրիդային իրադարձություններ 'BD սխեմաների արտահոսք և կոշտ կապ։
Ներքին և ինտեգրացիոն իրադարձությունների խառնուրդը 'հրապարակեք կայունացված «վիտրինը»։
Chek Lister-ը վաճառելու համար
- Հայտնաբերվել են ագրեգատները, ինվարանտները և իրադարձությունները (անուններ, տարբերակներ, սխեմաներ)։
- Event Store-ը կարգավորում է ագրեգատի և optimistic concurrency-ի սահմաններում։
- Միացեք կեղևները և դրանց վերամշակման պլանը։
- Idempotent պրոյեկտները, կան DLQ և լագայի չափումներ։
- Սխեմաները վալիդացվում են CI-ի վրա, տարբերակների քաղաքականությունը փաստագրված է։
- PII նվազագույն է, դաշտերը կոդավորված են, կա «մոռացման» ռազմավարություն։
- Պրոյեկցիաների ռեպլեյը ստուգված է պատին; վերականգնման ծրագիր կա։
- Dashbords: Appenda արագություն, պրոյեկցիաների լագը, օգտագործման սխալները, գետերի մասնաբաժինը։
Արդյունքը
Event Sourcing-ը ստեղծում է համակարգի պատմությունը առաջին կարգի արտեֆակտով, մենք արձանագրում ենք փաստերը, դրանցից մենք վերարտադրում ենք վիճակը և ազատորեն կառուցում ենք ցանկացած ներկայացում։ Սա տալիս է աուդիտ, փոփոխությունների դիմադրություն և վերլուծության ճկունություն 'ենթակա սխեմաների, մրցակցային վերահսկման և զգայուն տվյալների հետ աշխատելուն։