ఈవెంట్ సోర్సింగ్ (Event sourcing) మీ డేటాను పదేపదే ఓవర్రైట్ (overwrite) చేయవద్దని చెబుతుంది. సాంప్రదాయ CRUD అప్లికేషన్లో, యూజర్ యొక్క షిప్పింగ్ అడ్రస్ను అప్డేట్ చేయడం అంటే ఆ రో (row)ను కనుగొనడం, విలువను మార్చడం మరియు పాత స్థితిని తొలగించడం. ఈవెంట్ సోర్సింగ్ వేరే మార్గాన్ని అనుసరిస్తుంది. ఇది ప్రతి మార్పును ఒక మార్చలేని వాస్తవం (immutable fact)గా నిల్వ చేస్తుంది: ఒక యూజర్ ఖాతాను సృష్టించారు, వారి చిరునామాను అప్డేట్ చేశారు, వారి ఈమెయిల్ను ధృవీకరించారు. సిస్టమ్ యొక్క ప్రస్తుత స్థితి నేరుగా నిల్వ చేయబడదు. ఈ ఈవెంట్లను క్రమ పద్ధతిలో మళ్ళీ ప్లే చేయడం (replaying) ద్వారా దీనిని లెక్కిస్తారు.
ఈ ప్యాటర్న్ నిజమైన సమస్యలను పరిష్కరిస్తుంది. ఆడిట్ ట్రయల్స్ (Audit trails) ఉచిత ఉప-ఉత్పత్తులుగా మారుతాయి. మీరు గతంలోని ఏ క్షణంలోనైనా ఒక ఆర్డర్ యొక్క స్థితిని పునర్నిర్మించవచ్చు. సరిగ్గా ఏమి జరిగిందో మళ్ళీ ప్లే చేయడం ద్వారా మీరు డీబగ్ (debug) చేయవచ్చు. దీని వల్ల కలిగే నష్టం (trade-off) సంక్లిష్టత. మీరు ఇప్పుడు సాధారణ రోలకు బదులుగా ఫ్యాక్ట్స్ స్ట్రీమ్స్ (streams of facts), రీడ్ మోడల్స్ (read models) మరియు ఈవెంచ్యువల్ కన్సిస్టెన్సీ (eventual consistency)ని నిర్వహించాల్సి ఉంటుంది.
PostgreSQL మీ ఈవెంట్ స్టోర్గా పనిచేయగలదు. చాలా టీమ్లు ఇప్పటికే దీనిని ఉపయోగిస్తున్నాయి. ఇది ACID ట్రాన్సాక్షన్స్, ఫ్లెక్సిబుల్ పేలోడ్ల కోసం JSONB మరియు నిరూపితమైన బ్యాకప్ టూల్స్ను అందిస్తుంది. మొదటి రోజే మీరు Kafka, Cassandra లేదా ప్రత్యేకమైన ఈవెంట్-స్టోర్ డేటాబేస్ను ప్రవేశపెట్టాల్సిన అవసరం లేదు. మీ ఇన్ఫ్రాస్ట్రక్చర్ పరిధిని పెంచకుండానే, ఈవెంట్ సోర్సింగ్కు అవసరమైన ట్రాన్సాక్షనల్ గ్యారెంటీలు మరియు ఆడిట్ ట్రయల్స్ను ఒక సాధారణ Postgres ఇన్స్టాన్స్ మీకు అందిస్తుంది.
ఒక Postgres ఈవెంట్ స్టోర్ యొక్క రూపం
స్కీమా చాలా సరళంగా ఉండవచ్చు. కనీసం, ఈవెంట్లను యాపెండ్ (append) చేసే మరియు వాటిని ఎక్కడా అప్డేట్ చేయని ఒక టేబుల్ మీకు అవసరం. ఒక ప్రాక్టికల్ డిజైన్ ఇలా ఉంటుంది:
idఅనేది bigserial లేదా UUID గా, గ్లోబల్ ఆర్డరింగ్ కోసం ఉపయోగపడుతుంది.stream_idసంబంధిత ఈవెంట్లను గ్రూప్ చేయడానికి, ఉదాహరణకు ఒకే యూజర్ లేదా ఆర్డర్కు సంబంధించిన అన్ని మార్పులు.event_typeఅనేది ప్లెయిన్ టెక్స్ట్:UserEmailChanged,PaymentReceived,InventoryAdjusted.payloadఅనేది JSONB గా, ఆ సంఘటనకు సంబంధించిన నిర్దిష్ట డేటాను కలిగి ఉంటుంది.occurred_atటైమ్ జోన్ ప్రిసిషన్తో.- ప్రతి స్ట్రీమ్ కోసం
version, ఇది ఆప్టిమిస్టిక్ కన్కరెన్సీని (optimistic concurrency) అమలు చేస్తుంది.
మీరు అప్లికేషన్ కోడ్లో లేదా డేటాబేస్ కన్స్ట్రెయింట్ (constraint) ద్వారా ఇమ్మ్యూటబిలిటీ (immutability) నియమాన్ని అమలు చేయవచ్చు. (stream_id, version) పై ఒక యూనిక్ ఇండెక్స్ ఉండటం వల్ల ఇద్దరు రైటర్లు ఒకే సీక్వెన్స్ నంబర్ను యాపెండ్ చేయకుండా నిరోధించవచ్చు. ఒక కమాండ్ వచ్చినప్పుడు, మీరు ఆ స్ట్రీమ్ యొక్క ప్రస్తుత వెర్షన్ను చదివి, దానిని పెంచి, ఒక ట్రాన్సాక్షన్లో కొత్త ఈవెంట్ను ఇన్సర్ట్ చేస్తారు. ఒకవేళ మరొక ప్రాసెస్ మీకంటే ముందే దానిని పూర్తి చేస్తే, యూనిక్ కన్స్ట్రెయింట్ ఫెయిల్ అవుతుంది, అప్పుడు మీరు కమాండ్ను మళ్ళీ ప్రయత్నించవచ్చు లేదా తిరస్కరించవచ్చు.
ఒక స్పష్టమైన ఉదాహరణను పరిశీలిద్దాం. మీరు ఒక ఇన్వెంటరీ సిస్టమ్ను నడుపుతున్నారు. quantity కాలమ్తో ఉన్న ఒకే inventory రోకు బదులుగా, మీరు inventory_events టేబుల్కు ఈవెంట్లను యాపెండ్ చేస్తారు. ItemReceived పది యూనిట్లను జోడిస్తుంది. ItemReserved రెండు యూనిట్లను తీసివేస్తుంది. ItemShipped మూడు యూనిట్లను తీసివేస్తుంది. SKU-42 యొక్క ప్రస్తుత స్టాక్ తెలుసుకోవడానికి, మీరు సంబంధిత ఈవెంట్ పేలోడ్లను కూడాలి (sum). మూడు రోజుల క్రితం స్టాక్ ఎంత ఉందో తెలుసుకోవడానికి, మీరు ఆ టైమ్స్టాంప్ వరకు మాత్రమే కూడాలి. గత మంగళవారం మీ షిప్పింగ్ లాజిక్లో ఏదైనా బగ్ వల్ల తప్పు జరిగితే, అసలైన స్థితిని తెలుసుకోవడానికి మీరు సరిచేసిన కోడ్ ద్వారా ఈవెంట్లను మళ్ళీ ప్లే చేయవచ్చు. ఒక సాధారణ UPDATE స్టేట్మెంట్తో మీరు అలా చేయలేరు.
మిమ్మల్ని ఇబ్బందుల నుండి కాపాడే సూత్రాలు
Postgres పై నిర్మించడం వల్ల క్రమశిక్షణ అవసరం ఉండదు అని కాదు. ఈ క్రింది సూత్రాలు ఈవెంట్-సోర్స్డ్ సిస్టమ్లకు నేరుగా వర్తిస్తాయి.
సరళంగా ఉంచండి. సంక్లిష్టత విశ్వసనీయతను దెబ్బతీస్తుంది. ఒక వర్కింగ్ ఫ్లోను పూర్తి చేసేలోపే ఒక జనరిక్ ఈవెంట్ ఫ్రేమ్వర్క్ను నిర్మించాలనే కోరికను అదుపులో ఉంచుకోండి. విలువను నిరూపించడానికి ఒకే ఒక టేబుల్, ఈవెంట్లను యాపెండ్ చేయడానికి ఒక రిపోజిటరీ ఫంక్షన్ మరియు రీడ్ మోడల్స్ను నిర్మించడానికి ఒక ప్రొజెక్షన్ వర్కర్ సరిపోతాయి. ఏదైనా స్పష్టమైన సమస్య ఎదురైనప్పుడు మాత్రమే కొత్త టూల్స్ను జోడించండి.
చిన్నగా ప్రారంభించండి. మీ మొత్తం మోనోలిత్ను (monolith) మళ్ళీ రాయకండి. ఆడిట్ ట్రయల్ వల్ల కలిగే అదనపు శ్రమను భరించగలిగే ఒక బౌండెడ్ కాంటెక్స్ట్ను (bounded context) ఎంచుకోండి. బిల్లింగ్ లెడ్జర్, వర్క్ఫ్లో ఇంజిన్ లేదా ఇన్వెంటరీ రిజర్వేషన్ సిస్టమ్ మంచి అభ్యర్థులు. ఆ ఒక్క పైప్లైన్ను ఎండ్-టు-ఎండ్ నిర్మించండి. దానిని ప్రొడక్షన్లో నడవనివ్వండి. ఆ తర్వాత విస్తరించాలా వద్దా అని నిర్ణయించుకోండి.
ముందుగా విజయాన్ని నిర్వచించండి. ఈవెంట్ సోర్సింగ్ అనేది డిఫాల్ట్ ఆర్కిటెక్చర్ కాదు; ఇది నిర్దిష్ట అవసరాలకు ఒక పరిష్కారం. మీ అవసరం కేవలం తాజా స్థితిని ట్రాక్ చేయడం మాత్రమే అయితే, CRUD వేగంగా మరియు చౌకగా ఉంటుంది. మీకు టెంపోరల్ క్వెరీస్ (temporal queries), కఠినమైన ఆడిటబిలిటీ లేదా అవసరాన్ని బట్టి రీడ్ మోడల్స్ను మళ్ళీ నిర్మించే సామర్థ్యం కావాలంటే, అప్పుడు ఈవెంట్లు ఉపయోగపడతాయి. మీరు దేనిని పరిష్కరిస్తున్నారో నిర్ణయించుకున్నాకే దీనికి కట్టుబడి ఉండండి.
ఆప్టిమైజ్ చేసే ముందు కొలవండి. సాధారణ హార్డ్వేర్పై ఆధునిక PostgreSQL ఒక సాధారణ యాపెండ్-ఓన్లీ టేబుల్తో సెకనుకు వేలకొద్దీ ఈవెంట్లను స్వీకరించగలదు. సరళమైన పరిష్కారాలు పనిచేయడం లేదని మీ మానిటరింగ్ నిరూపించే వరకు మీ ఈవెంట్ స్టోర్ను షార్డ్ (shard) చేయవద్దు లేదా సంక్లిష్టమైన పార్టిషనింగ్ స్కీమ్లను ప్రవేశపెట్టవద్దు. మీరు క్వెరీ చేసే ఫీల్డ్లను ఇండెక్స్ చేయండి. యాపెండ్-ఓన్లీ వర్క్లోడ్ల కోసం autovacuumను ట్యూన్ చేయండి. ఆ తర్వాత మళ్ళీ కొలవండి.
అన్నింటినీ పరీక్షించండి. మీ ఈవెంట్ హ్యాండ్లర్లను యూనిట్ టెస్ట్ చేయండి. అపెండ్ పాత్ను (append path) ఇంటిగ్రేషన్ టెస్ట్ చేయండి. అన్నింటికంటే ముఖ్యంగా, ఫెయిల్యూర్ సినారియోలను పరీక్షించండి. రెండు నోడ్లు ఒకే స్ట్రీమ్కు ఒకేసారి అపెండ్ చేసినప్పుడు ఏమవుతుంది? ఒక ప్రొజెక్షన్ వర్కర్ బ్యాచ్ మధ్యలో క్రాష్ అయినప్పుడు ఏమవుతుంది? మీ ఆప్టిమిస్టిక్ కన్కరెన్సీ (optimistic concurrency) మరియు మీ 'at-least-once delivery' గ్యారెంటీలను ధృవీకరించే పరీక్షలను రాయండి.
ప్రొడక్షన్లో పర్యవేక్షించండి. ఈవెంట్స్ టేబుల్ పెరుగుతూ ఉంటుంది. అప్డేట్లు రో కౌంట్ను స్థిరంగా ఉంచే నార్మలైజ్డ్ స్కీమా లాగా కాకుండా, ఈవెంట్ సోర్సింగ్ ఉద్దేశపూర్వకంగానే అడిటివ్ (additive) గా ఉంటుంది. టేబుల్ సైజు, డిస్క్ I/O, మరియు మీ రైట్ మోడల్ (write model) మరియు మీ రీడ్ మోడల్ ప్రొజెక్షన్ల మధ్య ఉన్న లాగ్ (lag) ను ట్రాక్ చేయండి. వినియోగదారులు పాత డేటాను గమనించకముందే ప్రొజెక్షన్ లాగ్ కోసం అలర్ట్లను సెట్ చేయండి.
మాన్యువల్ పనులను ఆటోమేట్ చేయండి. మాన్యువల్ స్కీమా మార్పులు, మాన్యువల్ ప్రొజెక్షన్ రీబిల్డ్లు మరియు మాన్యువల్ ఈవెంట్ రీప్లేలు టైమింగ్ బాంబులు వంటివి. మీ మైగ్రేషన్ వ్యూహాన్ని స్క్రిప్ట్ చేయండి. మీరు ఈవెంట్ స్కీమాను అభివృద్ధి చేస్తే, పాత ఈవెంట్లను అర్ధరాత్రి ఎవరి ప్రమేయం లేకుండా కొత్త లాజిక్ ద్వారా రీప్లే చేయడానికి వీలుగా అప్కాస్టింగ్ (upcasting) లేదా ట్రాన్స్ఫర్మేషన్ను ఆటోమేట్ చేయండి.
మీ ఎంపికలను డాక్యుమెంట్ చేయండి. నిర్దిష్ట స్ట్రీమ్లు ఎందుకు ఉన్నాయి, ప్రతి ఈవెంట్ రకం యొక్క అర్థం ఏమిటి మరియు టీమ్ ఎప్పుడు ఈవెంట్ల కంటే CRUDని ఎంచుకోవాలి అనే విషయాలను రాసి ఉంచండి. ఈవెంట్ సోర్సింగ్ వల్ల కాగ్నిటివ్ లోడ్ (cognitive load) పెరుగుతుంది. మంచి డాక్యుమెంటేషన్ వల్ల కొత్త ఇంజనీర్లు తప్పుగా ఊహించి, కీలకమైన స్ట్రీమ్కు తప్పుగా రూపొందించబడిన (malformed) ఈవెంట్లను అపెండ్ చేయకుండా నిరోధించవచ్చు.
నెలల సమయాన్ని వృధా చేసే ఉచ్చులు
ఈవెంట్ సోర్సింగ్ డయాగ్రామ్లో చూడటానికి చాలా చక్కగా అనిపించినా, ప్రొడక్షన్లో మాత్రం చాలా కష్టంగా ఉండవచ్చు. ఈ ఉచ్చుల పట్ల జాగ్రత్తగా ఉండండి.
సంక్లిష్టతను తక్కువ అంచనా వేయడం. స్టేట్ను రీబిల్డ్ చేయడానికి ఈవెంట్లను రీప్లే చేయడం భావనపరంగా సరళమైనది. కానీ ఐడెంపోటెన్సీ (idempotency) నిర్వహించడం, పనితీరు కోసం స్నాప్షాటింగ్ (snapshotting) చేయడం మరియు అగ్రిగేట్ల మధ్య కంపెన్సేటింగ్ ట్రాన్సాక్షన్లను (compensating transactions) నిర్వహించడం అంత సులభం కాదు. మీ సిస్టమ్ను చిన్న చిన్న భాగాలుగా విభజించండి. ఒక సమయంలో ఒక స్ట్రీమ్ను పరిష్కరించండి.
ఓవర్-ఇంజనీరింగ్. మీ ఈవెంట్ వాల్యూమ్ ఏదో ఒక రోజు అవసరమవుతుందని ఊహించి, మల్టీ-నోడ్ Kafka క్లస్టర్ను సిద్ధం చేయకండి. Postgres మిమ్మల్ని ఆశ్చర్యపరిచే విధంగా చాలా దూరం తీసుకెళ్లగలదు. మీ ప్రస్తుత సెటప్లో పరిష్కరించలేని సమస్య (bottleneck) ఉన్నప్పుడు మాత్రమే కొత్త ఇన్ఫ్రాస్ట్రక్చర్ను పరిచయం చేయండి.
టెక్నికల్ డెట్ (technical debt) ను విస్మరించడం. పాత ఈవెంట్ స్కీమాలు ఎప్పటికీ అలాగే ఉండిపోతాయి. మీరు మీ OrderCreated పేలోడ్ను మార్చినప్పటికీ, పాత రూపంలో పది మిలియన్ల చారిత్రక ఈవెంట్లు ఉంటాయి. ఈ డెట్ను ట్రాక్ చేయండి. బ్యాక్వర్డ్-కంపాటబుల్ (backward-compatible) రీడర్లను లేదా మైగ్రేషన్ స్క్రిప్ట్లను ప్లాన్ చేయండి. పాత ఈవెంట్ల భారం ప్రతి కొత్త ఫీచర్ను నెమ్మదింపజేయనివ్వకండి.
టీమ్ నడపలేని సాధనాలను ఎంచుకోవడం. ఒక వ్యక్తి మాత్రమే అర్థం చేసుకుంటే, ఉత్తమమైన ఆర్కిటెక్చర్ కూడా విఫలమవుతుంది. మీ టీమ్కు Postgres మరియు SQL తెలిస్తే, అక్కడి నుండే ప్రారంభించండి. మీరు ఒక ప్రత్యేకమైన ఈవెంట్ స్టోర్ను పరిచయం చేస్తే, తెల్లవారుజామున రెండు గంటల సమయంలో కూడా దానిని డీబగ్ (debug) చేయడానికి అవసరమైన ఆపరేషనల్ నైపుణ్యం మీకు ఉందని నిర్ధారించుకోండి.
ఒక ఆచరణాత్మక ప్రారంభ బిందువు
ఈ విధానం మీ సమస్యకు సరిపోతుంటే, ఐదు క్వార్టర్ల రీరైట్ కోసం వేచి చూడకండి. ఈ వారమే ప్రారంభించండి.
మీ ప్రస్తుత వ్యవస్థలను ఆడిట్ చేయండి. ఆడిట్ ట్రైల్ (audit trail) నిజమైన సమస్యను పరిష్కరించగల చోటును కనుగొనండి. బహుశా అది ప్రస్తుతం ఒకే status కాలమ్ను కలిగి ఉన్న ఆర్డర్ స్టేట్ మెషీన్ కావచ్చు. లేదా బ్యాలెన్స్ కరెక్షన్ల కోసం మాన్యువల్ డేటాబేస్ ప్యాచెస్ అవసరమయ్యే ఫైనాన్షియల్ లెడ్జర్ కావచ్చు. స్టేట్ను ఓవర్రైట్ చేయడం వల్ల మీకు ఇబ్బంది కలిగించిన ఒక లోపాన్ని ఎంచుకోండి.
ఆ తర్వాత ఈరోజు మీరు చేయగలిగే ఒక చిన్న మెరుగుదలని ఎంచుకోండి. ఒక ఈవెంట్ టేబుల్ను సృష్టించండి. ఒక స్ట్రీమ్ను మోడల్ చేయండి. ఆ ఈవెంట్ల నుండి రీడ్ మోడల్ను నిర్మించే ఒక ప్రొజెక్షన్ను రాయండి. దానిని ఒక ఫీచర్ ఫ్లాగ్ (feature flag) వెనుక డిప్లాయ్ చేయండి. అది నిజమైన ట్రాఫిక్ను ఎలా హ్యాండిల్ చేస్తుందో గమనించండి.
PostgreSQLతో ఈవెంట్ సోర్సింగ్ అనేది మ్యాజిక్ కాదు. వస్తువులు ఎక్కడ ఉన్నాయో మాత్రమే కాకుండా, అవి అక్కడికి ఎలా చేరుకున్నాయో కూడా తెలుసుకోవాల్సిన టీమ్ల కోసం ఇది ఒక ఆచరణాత్మక సాధనం. నెమ్మదిగా నిర్మించండి, నిజాయితీగా కొలవండి మరియు మీ అసలు అవసరాలే ఆర్కిటెక్చర్కు మార్గదర్శకంగా ఉండనివ్వండి.
