- रिलेशनल CRUD मॉडल storage structure को तो अच्छी तरह दिखाता है, लेकिन business process को overwrite करना आसान बना देता है, इसलिए सिस्टम में वास्तव में क्या हुआ इसे track करना मुश्किल हो जाता है
- Event Sourcing हर operation के बाद बने immutable events को Event Stream के रूप में रखता है, और बाद के decisions में उस list को पढ़कर current state तय करता है
- Modeling पहले events खोजने से शुरू होती है, फिर user के action intent यानी command और business rules को जोड़कर process को समझने की दिशा में आगे बढ़ती है
- मौजूदा relational data में event candidates खोजते समय status columns, date columns, nullable है या नहीं, 1:N relationships को देखें, लेकिन सिर्फ status values से complete history reconstruct हो सकती है ऐसा मानना जोखिम भरा है
- जब केवल final state वाला data migrate करना हो, तो past events को जबरन reconstruct करने के बजाय Order Imported जैसे explicit import event से शुरू करना और safe environment में repeatedly validate करना ज्यादा practical है
CRUD डेटा से event-centric model की तरह देखना
- Relational data model दिखाता है कि कौन सा data store किया जाता है, लेकिन system के अंदर क्या हुआ और processes कैसे interact करते हैं, यह समझना मुश्किल होता है
- मौजूदा CRUD तरीका data को overwrite करते हुए महत्वपूर्ण business information खो सकता है
- Event Sourcing storage size से ज्यादा information quality को प्राथमिकता देता है, और हर operation के बाद हुई fact को event के रूप में store करता है
Event Sourcing का basic model
- Event पहले से हो चुकी घटना का fact है, और एक बार store होने के बाद बदला नहीं जा सकने वाला immutable data है
- Event Stream किसी एक record के लिए हुई सभी चीजों की ordered list है
- Past events को modify नहीं किया जा सकता, लेकिन अंत में नया event जोड़कर पिछली गलती को ठीक किया जा सकता है
- Decision लेते समय event list को पढ़कर और verify करके current state और next action तय किया जाता है
Process modeling का क्रम
- Modeling सबसे पहले event discovery से शुरू होती है
- इसके बाद command खोजकर define किया जाता है कि कौन सा action execute करने का intent है
- आखिर में business rules को व्यवस्थित किया जाता है
- Events technical और business stakeholders के लिए process को साथ में समझने का central axis बनते हैं
- Alberto Brandolini के EventStorming की तरह events, commands, और rules को साथ देखकर process समझा जा सकता है
मौजूदा relational data में event candidates खोजना
-
1. Status columns देखना
- status column की values data lifecycle के stages को reflect कर सकती हैं
- अगर order में initiated, shipped, paid जैसी states हों, तो वे क्रमशः Order Initiated, Order Shipped, Order Paid event candidates हो सकते हैं
- हालांकि status value business process की flattened interpretation हो सकती है, इसलिए इसे complete नहीं मानना चाहिए
- Event names को Order Created, Order Updated, Order Deleted जैसे CRUD operations के आधार पर रखना avoid करना चाहिए
- State Obsession को avoid किए जाने वाले तरीके के रूप में पेश किया गया है
-
2. Date columns जांचना
- Date columns process lifecycle में important occurrence points बता सकते हैं
- CreatedDate और ModifiedDate बहुत जानकारी नहीं देते, लेकिन ShipmentDate, DeliveryDate, OrderPlacementDate बेहतर clues देते हैं
- उदाहरण:
- ShipmentDate Order Shipped event introduce करने का clue हो सकता है
- OrderPlacementDate संकेत देता है कि Order Initiated की तुलना में Order Placed बेहतर नाम हो सकता है
- DeliveryDate दिखाता है कि Order Delivered event की जरूरत हो सकती है
- ऐसे clues को domain experts के साथ confirm करके real business process से align करना चाहिए
-
3. Columns nullable हैं या नहीं, इसका analysis करना
- non-nullable columns वह data हैं जो हमेशा provide किया जाना चाहिए
- nullable columns बाद में किसी दूसरे operation में provide किए जा सकते हैं या optional values हो सकते हैं
- अगर Ordering Process में कोई required column है, तो वह data पहले Order Initiated event में भी शामिल होना चाहिए
- एक single event type हमेशा stream का starting point नहीं होता; starting events कई हो सकते हैं
-
4. कई 1:N relationships वाली tables खोजना
- Stream boundaries खोजने के लिए 1:N relationships ज्यादा रखने वाली tables से देखना शुरू किया जा सकता है
- बहुत सारी “one” relationships रखने वाली tables stream type candidates बनती हैं
- यह भी logically judge करना चाहिए कि data independently exist कर सकता है या नहीं
- shipment, order से अलग process हो सकता है
- order line का order के बिना exist करना मुश्किल है
- Boundaries पर चर्चा की process में और events discover किए जा सकते हैं और process की understanding बढ़ सकती है
Migration के दौरान false events न बनाना
- Relational data flattened final state होता है, इसलिए सिर्फ उस state को देखकर वास्तव में हुई detailed past events को reverse-engineer करने की कोशिश fail हो सकती है या inaccurate हो सकती है
- छोटे-छोटे past events को जबरन बनाने के बजाय, current state पूरी और interpretation code रखने वाला Order Imported event explicitly provide करना बेहतर है
- Import event साफ दिखाता है कि data किस तरीके से आया, और problem solving व diagnosis में important हो सकता है
Prototype से validate करना
- Migration को safe environment में prototype के रूप में try करना चाहिए, और देखना चाहिए कि model वास्तव में कैसे behave करता है
- Results को expected values से compare करते हुए iteratively revise करना चाहिए
- जल्दबाज़ी किए बिना, existing information खोए बिना, और उसी information के आधार पर आगे model improve करने का तरीका जरूरी है
- Relational data से document-based में move करने की general strategy General strategy for migrating relational data to document-based से भी जुड़ी है
1 टिप्पणियां
Hacker News की राय
2c: अगर ऐप के दूसरे हिस्सों में भी PostgreSQL की जरूरत है, तो event data को भी PostgreSQL + FOSS reporting tools (Apache Superset, Metabase आदि) में store करें और लगभग 2TB तक उसी पर टिके रहना बेहतर है
उसके बाद यह तय करें कि क्या पूरे 2TB को online रखना जरूरी है, या दिन/घंटे के हिसाब से summary ही काफी है। अगर दूसरा विकल्प है, तो PostgreSQL के साथ जारी रहना पर्याप्त होगा[1]
एक customer 10TB+ scale पर प्रति सेकंड 1,500 events, प्रति record 600 bytes (indexing से पहले रोज 80GB) handle करता है, सिर्फ 2 दिन का detailed data online रखता है, बाकी को summarize करता है और detail को S3 में ले जाकर Athena SQL से लगातार query करता है[2]
customer reporting portal समेत कुल cost 2 हजार dollar से कम है, और AWS RDS multi-AZ automatic failover (db.m7g.2xlarge) पर inserts और reporting queries दोनों handle होते हैं, फिर भी load 2% से कम है। business team खुद charts और graphs बनाती है, इसलिए 1 engineer maintenance पर महीने में 5 घंटे से कम लगाता है
proprietary tools इस्तेमाल करने पर कुछ charts “built-in” मिल जाते हैं, लेकिन pgsql इस्तेमाल करने पर data एक जगह रहता है, सीखने के लिए एक ही system, online maintain/replicate/backup/recover करने के लिए एक ही system, secure/scale करने के लिए एक ही system, manage करने के लिए एक ही vendor, और इस system को जानने वाले लाखों engineers हैं
Preset या Metabase जैसे systems में 12 charts बनाने में एक घंटा काफी है, और non-technical लोग भी यह कर सकते हैं
संदर्भ के लिए, bias हो सकता है, लेकिन 20+ साल से databases और reporting systems को आते-जाते देखा है, और अच्छा पुराना PostgreSQL हर साल बेहतर होता जा रहा है
https://instances.vantage.sh/aws/rds/db.m7g.2xlarge?region=u...
[1] सच में जरूरत पड़े तो और scale करने के लिए PostgreSQL-compatible systems भी हैं। Aurora 3–5x, TimescaleDB 10x, CitusDB 10x+ तक scale कर सकते हैं। हर एक में थोड़ा non-standard होने की कीमत है, इसलिए जब तक सच में जरूरत न हो, recommend नहीं करूंगा
[2] customer reporting dashboard को sub-second response चाहिए, और PostgreSQL indexed summary tables query करके यह देता है। Athena parallel scan से लगभग 1–2 सेकंड में response देता है
store करने से पहले data के snapshots बनाए रखें, किसी specific event order को identify/collect करने वाली scripts रखें, फिर इंसान review करके नए logic के असर को bulk में retroactively apply कर दे
https://django-simple-history.readthedocs.io/en/latest/ जैसे tools audit tables बनाने के लिए आधे भरोसेमंद और simple solution हैं, और अगर direct database access तक audit करना हो तो Postgres triggers भी जोड़े जा सकते हैं
theory में event sourcing पसंद है, लेकिन practice में नया CRUD flow जोड़ने या early-to-mid-stage startup को unexpected situations में अक्सर करनी पड़ने वाली interventions/hotfixes को जल्दी और reliably deploy करने के लिए बहुत ज्यादा boilerplate चाहिए होता है
अगर payment processing rails implement करने जैसा काम नहीं है, तो event sourcing शायद सही choice न हो
https://news.ycombinator.com/item?id=17817375 (2018) में भी event sourcing की कमियों पर अच्छी discussion है
PostgreSQL की इकलौती problem यह है कि insert side पर interesting scalability issue है। आम तौर पर event source और DB के बीच queue रखने की सलाह दी जाती है
{id:uuid,created_at:timestamptz,data:jsonb}definition वाली table रखने जैसा हैखासकर अगर event structure विविध हो और event definitions बदलती रहें, तो JSONB index features का पूरा फायदा लेना मुश्किल होता है
शायद इस document को और अच्छी तरह समझना होगा: https://www.postgresql.org/docs/current/datatype-json.html#J...
पहले हमारी टीम ने event sourcing पर गंभीरता से विचार किया था, लेकिन मुझे यह समस्या की तलाश में निकला समाधान जैसा लगा
यह हमारे लिए भी काम कर सकता था, लेकिन फायदे तुरंत स्पष्ट नहीं थे, और नया तरीका अपनाने से आने वाले जोखिम और trial-and-error प्रोजेक्ट या कंपनी के लिए सबसे अच्छे नहीं लग रहे थे, इसलिए अंततः हमने इसे छोड़ दिया
हो सकता है यह ऐसा फैसला रहा हो जैसे सीखने का मौका देने वाले टूल को छोड़ देना, लेकिन पीछे से लोमड़ी पीछा नहीं कर रही थी, इसलिए उस rabbit hole में न जाने का मुझे अफसोस नहीं है
यह समाधान जिस “समस्या” को हल करता है, वही है
लेकिन ज्यादातर मामलों में सामान्य database इस्तेमाल करके पुराने बदलावों का इतिहास auxiliary table में रख देना काफी है। तब main database एक तरह के materialized view की तरह काम करता है
मुझे बहुत बड़ी शिकायत नहीं है, और मैं इसे गलत चुनाव भी नहीं मानता, लेकिन data model में बदलावों को handle करने के तरीके में समस्याएं आती हैं
आजकल software जिस तरह बनाया जाता है, उसके मुकाबले data storage के ज्यादातर तरीके पीछे रह गए लगते हैं, और events व queues जैसी चीजें मौजूदा systems के ऊपर जरूरी features जोड़कर बनाए गए नतीजे हैं
आज कई data relationships कई services के बीच, यानी database के बाहर, बनते हैं। कई organizations का modern IT environment ऐसा ही दिखता है
business की कई teams को support करने वाला internal master data होता है, और काम को आसान बनाने के लिए यह 300 से ज्यादा IT systems और applications के साथ interact करता है
microservices इस्तेमाल करने पर business logic और data model को साफ-सुथरा रखना आसान होता है, लेकिन उसके बदले events, queues, data state और dependent stores तक manage करने पड़ते हैं, और अभी यह बहुत जटिल है
मुझे SQL पसंद है, लेकिन सच कहूं तो आजकल हम जो systems बनाते हैं, वे शायद SQLite में डाल देने पर भी लगभग पर्याप्त होंगे
ऐसी चर्चाओं में जो हिस्सा छूट जाता है, वह यह है कि event-driven architecture कब उपयुक्त है
संक्षेप में कहें तो अगर customer ने कुछ किया है और response की उम्मीद करता है, तो वह event-driven नहीं, बस request/response है
event-driven तब है जब out-of-band कुछ होता है। जैसे GitHub पर code push करने से build trigger होना
इस उदाहरण में updated code देखने के लिए page refresh करना request/response है, लेकिन queue में गया CI build event-driven है
उम्मीद है यह मदद करेगा
event sourcing या event-driven में भी request-response, inline, blocking, circular flows बनाए जा सकते हैं
उल्टा, event sourcing या event-driven के बिना भी workers, queues, actors, multithreading जैसे तरीकों से asynchronous processing अच्छी तरह बनाई जा सकती है
domain events को model करना domain experts के साथ हल की जाने वाली समस्या समझाने में उपयोगी है, और solution plan करते समय इसे documentation में छोड़ देना पर्याप्त हो सकता है
लंबे समय तक चलने वाली state machine का audit trail देने वाला system वास्तव में implement करना हो, तो Temporal.io या durable functions जैसी चीजें इस्तेमाल करना शायद बेहतर होगा
ये tools internal persistence के लिए event sourcing इस्तेमाल करते हैं, और functionality को orchestrate करने वाले code (workflows) और वास्तविक दुनिया से interact करने वाले code (activities) पर अलग-अलग constraints जोड़कर ऐसा programming model देते हैं जो duplicate removal और idempotency के बारे में सोचने को मजबूर करता है
इस समस्या से पार पाने के तरीकों पर सुझाव सुनना चाहूंगा
अवधारणा दिलचस्प है, लेकिन लेख यह ठीक से नहीं समझाता कि यह काम कैसे करता है
मैं जानना चाहता हूँ कि event stream से current state को कुशलता से कैसे फिर से बनाया जाता है, और event stream को database में कैसे model किया जाता है
https://www.youtube.com/watch?v=gG6DGmYKk4I
https://www.youtube.com/watch?v=jnDchr5eabI
https://www.youtube.com/watch?v=ArcypYS5XBQ
https://www.youtube.com/watch?v=uODSwR2CIV4
GitHub पर samples भी maintain कर रहे हैं
https://github.com/oskardudycz/EventSourcing.NetCore
https://github.com/oskardudycz/EventSourcing.NodeJS
https://github.com/oskardudycz/EventSourcing.JVM
पहला, ऐसी databases इस्तेमाल करना जो इसी use case के लिए design की गई हों। Google BigQuery, Amazon Redshift, ClickHouse वगैरह हैं
सारा current data मूल रूप से किसी न किसी तरह का aggregation है। दूसरे शब्दों में, यह event database पर group-by query जैसा है
जब events मौजूद हों, तो aggregation query से current state या past state को technically फिर से बनाया जा सकता है, इसलिए यह बात समझ में आती है
दूसरा, relational store का नाम बदलकर event system के बगल में मौजूद cache layer कहना है
functionally यह वही चीज़ है, लेकिन उन लोगों के लिए warning light नहीं जलती जो हर चीज़ को event-driven बनाने पर अड़े रहते हैं
लेख में जिस architecture का वर्णन है, वह सच में मौजूद है। बस यह बेहद जटिल है, इसलिए इसका इस्तेमाल करने वाली services आम तौर पर बहुत targeted काम करती हैं। Google Analytics, Datadog, Splunk जैसी चीज़ें सोचें
अलग-अलग requirements के हिसाब से अलग-अलग systems में अलग-अलग states बनाई जा सकती हैं
मान लें आप shopping system बना रहे हैं; purchases और customers होने पर एक service events पढ़कर finance purposes के लिए relational tables बना सकती है
दूसरी service events पढ़कर customer data का key-value store बना सकती है, और तीसरी service product search के लिए OpenSearch service चला सकती है
event stream एक list है। Kafka जैसी purpose-built चीज़ इस्तेमाल करें तो यह कई lists, यानी topics और partitions वगैरह बन जाती है
लेकिन वह भी relational model के अंदर हल किया जा सकता है
यह बस top-down vs bottom-up, या custom vs general-purpose का फर्क है
top-down business domain से शुरू करता है, और implementation को available technologies, tools और vendors पर map करता है
bottom-up available technologies, tools और vendors से शुरू करता है, और उन्हें जोड़कर काम करने वाला solution बनाता है
custom में DDD, CQRS/ES, Sagas, TBUI (task-based/driven UI), GraphQL, algebraic data types वगैरह आते हैं
general-purpose में RDBMS, CRUD, REST, ACID transactions, CDC, general-purpose admin UI, no-code/low-code, limited/general-purpose types वगैरह आते हैं
मैं तो बस अच्छे पुराने तरीके वाला relational data इस्तेमाल करता रहूँगा
event-based architecture से मैं सहमत हूँ, लेकिन लगता है यह लेख अपनी बात पहुँचाने में संघर्ष करता है
मैं data relationships और business actions के फर्क पर ध्यान दूँगा
जब आप actions और business activity के नजरिये से सोचना शुरू करते हैं, तो operational relational data store से दूर जाने की दिशा कहीं ज्यादा साफ हो जाती है
event sourcing में कई अच्छी properties हैं, इसलिए यह दिलचस्प है
लेकिन क्या फिर भी relations की जरूरत नहीं होती? अगर हाँ, तो वे relations implement कैसे होते हैं?
अगर जवाब है “सब कुछ application layer code में implicitly है”, तो इसे स्वीकार करना मुश्किल है
फिर भी relations को query करने, relational views को up-to-date रखने, या कुछ ऐसा ही चाहिए होता है
relations persistence model का core न भी हों तो ठीक है, लेकिन data layer में कहीं न कहीं उन्हें implement होना चाहिए; यहाँ उसका जिक्र दिखाई नहीं देता
Firestore में भी यही समस्या है। हर कोई relations को किसी न किसी तरह संभालता है, लेकिन अंत में यह non-scalable spaghetti application code बन जाता है
अगर आप functional programming से परिचित हैं, तो यह मूल रूप से event stream को एक state में fold करने वाले fold operation जैसा ही है
पहले event sourcing systems के साथ काम करने के अनुभव से, explicitly stored event history होने का फायदा है, लेकिन complexity भी बहुत बढ़ जाती है
read models असल में कैसे generate किए जाएँ, model versions कैसे manage किए जाएँ, read models के snapshots रखे जाएँ या नहीं—ऐसे सवाल उठते हैं
मेरे अनुभव में, जिन ज्यादातर contexts में यह pattern लागू किया गया, वहाँ added complexity उसके लायक नहीं थी
जरूरत command queue की है। command events, domain events नहीं होते