इवेंट सोर्सिंग स्टोरेज के रूप में RDBMS का उपयोग करना


119

अगर मैं इवेंट सोर्सिंग डेटा को स्टोर करने के लिए RDBMS (जैसे SQL सर्वर) का उपयोग कर रहा था, तो स्कीमा कैसा दिख सकता है?

मैंने कुछ भिन्नताओं को एक सार अर्थ में बात करते देखा है, लेकिन कुछ भी ठोस नहीं है।

उदाहरण के लिए, मान लीजिए कि एक "उत्पाद" इकाई है, और उस उत्पाद में परिवर्तन इस प्रकार हो सकता है: मूल्य, लागत और विवरण। मैं उलझन में हूँ कि क्या मैं:

  1. एक "ProductEvent" तालिका है, जिसमें एक उत्पाद के लिए सभी फ़ील्ड हैं, जहां प्रत्येक परिवर्तन का मतलब है कि तालिका में एक नया रिकॉर्ड है, साथ ही "कौन, क्या, कहाँ, क्यों, कब और कैसे" (WWWWWH) को उपयुक्त मानते हैं। जब लागत, मूल्य या विवरण बदल दिया जाता है, तो उत्पाद का प्रतिनिधित्व करने के लिए एक पूरी नई पंक्ति।
  2. स्टोर उत्पाद की लागत, मूल्य और विवरण अलग-अलग तालिकाओं में एक विदेशी कुंजी संबंध के साथ उत्पाद तालिका में शामिल हो गए। जब उन गुणों में परिवर्तन होता है, तो WWWWWH के साथ नई पंक्तियों को उचित रूप में लिखें।
  3. स्टोर WWWWWH, प्लस एक "ProductEvent" तालिका में, इस घटना का प्रतिनिधित्व करने वाली एक क्रमबद्ध वस्तु, जिसका अर्थ है कि घटना को लोड किया जाना चाहिए, किसी दिए गए उत्पाद के लिए एप्लिकेशन स्टेट को फिर से बनाने के लिए मेरे एप्लिकेशन कोड में डी-सीरियल किए और फिर से खेला जाना चाहिए। ।

विशेष रूप से मैं ऊपर विकल्प 2 के बारे में चिंता करता हूं। चरम पर ले जाया गया, उत्पाद तालिका लगभग एक-तालिका-प्रति-संपत्ति होगी, जहां दिए गए उत्पाद के लिए एप्लिकेशन राज्य को लोड करना होगा, प्रत्येक उत्पाद घटना तालिका से उस उत्पाद के लिए सभी घटनाओं को लोड करने की आवश्यकता होगी। यह टेबल-धमाका मेरे लिए गलत है।

मुझे यकीन है कि "यह निर्भर करता है", और जब कोई एकल "सही उत्तर" नहीं है, तो मैं यह महसूस करने की कोशिश कर रहा हूं कि क्या स्वीकार्य है, और क्या पूरी तरह से स्वीकार्य नहीं है। मुझे यह भी पता है कि NoSQL यहां मदद कर सकता है, जहां घटनाओं को एक कुल रूट के खिलाफ संग्रहीत किया जा सकता है, जिसका अर्थ डेटाबेस से केवल एक ही अनुरोध है कि वह ऑब्जेक्ट को फिर से बनाने के लिए घटनाओं को प्राप्त कर सके, लेकिन हम NoSQL db का उपयोग नहीं कर रहे हैं इसलिए मैं विकल्प के लिए चारों ओर महसूस कर रहा हूं।


2
अपने सबसे सरल रूप में: [इवेंट] {एग्रीगेटआईड, एग्रीगेटवॉर्शन, इवेंटपायोड}। कुल प्रकार की कोई आवश्यकता नहीं है, लेकिन आप वैकल्पिक रूप से इसे संग्रहीत करते हैं। ईवेंट प्रकार की कोई आवश्यकता नहीं है, लेकिन आप वैकल्पिक रूप से इसे संग्रहीत करते हैं। यह उन चीजों की एक लंबी सूची है जो कुछ भी हुआ है, कुछ और ही अनुकूलन है।
यवेस रेनहौट

7
निश्चित रूप से # 1 और # 2 से दूर रहें। एक बूँद के लिए सब कुछ नीचे क्रमबद्ध करें और इसे इस तरह से संग्रहीत करें।
जोनाथन ओलिवर

जवाबों:


109

इवेंट स्टोर को घटनाओं के विशिष्ट क्षेत्रों या गुणों के बारे में जानने की आवश्यकता नहीं होनी चाहिए। अन्यथा आपके मॉडल के प्रत्येक संशोधन से आपके डेटाबेस को स्थानांतरित करने में परिणाम होगा (ठीक उसी तरह जैसे पुराने जमाने की दृढ़ता पर आधारित है)। इसलिए मैं विकल्प 1 और 2 बिल्कुल नहीं सुझाऊंगा।

नीचे स्कीमा के रूप में Ncqrs में प्रयोग किया जाता है । जैसा कि आप देख सकते हैं, तालिका "इवेंट्स" संबंधित डेटा को CLOB (यानी JSON या XML) के रूप में संग्रहीत करता है। यह आपके विकल्प 3 से मेल खाता है (केवल यह कि "ProductEvents" तालिका नहीं है क्योंकि आपको केवल एक सामान्य "घटनाक्रम" तालिका की आवश्यकता है। Ncqrs में आपके Aggregate Roots की मैपिंग "EventSources" तालिका के माध्यम से होती है, जहां प्रत्येक EventSource एक वास्तविक से मेल खाता है। अलग-अलग रूट।)

Table Events:
    Id [uniqueidentifier] NOT NULL,
    TimeStamp [datetime] NOT NULL,

    Name [varchar](max) NOT NULL,
    Version [varchar](max) NOT NULL,

    EventSourceId [uniqueidentifier] NOT NULL,
    Sequence [bigint], 

    Data [nvarchar](max) NOT NULL

Table EventSources:
    Id [uniqueidentifier] NOT NULL, 
    Type [nvarchar](255) NOT NULL, 
    Version [int] NOT NULL

जोनाथन ओलिवर के इवेंट स्टोर कार्यान्वयन के एसक्यूएल हठ तंत्र में मूल रूप से एक बीओओबी क्षेत्र "पेलोड" के साथ "कमिट्स" नामक एक तालिका होती है। यह Ncqrs की तरह ही बहुत अधिक है, केवल यह कि यह द्विआधारी प्रारूप में घटना के गुणों को क्रमबद्ध करता है (जो, उदाहरण के लिए, एन्क्रिप्शन समर्थन को जोड़ता है)।

ग्रेग यंग एक समान दृष्टिकोण की सिफारिश करता है, जैसा कि ग्रेग की वेबसाइट पर बड़े पैमाने पर प्रलेखित है

उनके प्रोटोटाइप "घटनाक्रम" तालिका का स्कीमा पढ़ता है:

Table Events
    AggregateId [Guid],
    Data [Blob],
    SequenceNumber [Long],
    Version [Int]

9
अच्छा उत्तर! EventSourcing का उपयोग करने के बारे में मैं पढ़ता हूं मुख्य तर्क में से एक इतिहास को क्वेरी करने की क्षमता है। मैं एक रिपोर्टिंग टूल कैसे बनाने जा रहा हूं जो क्वेरी में कुशल है जब सभी दिलचस्प डेटा XML या JSON के रूप में क्रमबद्ध होते हैं? क्या टेबल आधारित समाधान की तलाश में कोई दिलचस्प लेख हैं?
मारिजान हाइजेंडवेल्ड

11
@MarijnHuizendveld शायद आप इवेंट स्टोर के खिलाफ क्वेरी नहीं करना चाहते हैं। सबसे आम समाधान होगा कि इवेंट हैंडलर के दो जोड़े को एक रिपोर्टिंग या बीआई डेटाबेस में घटनाओं को प्रोजेक्ट करें। इन हैंडलर के खिलाफ घटना के इतिहास को फिर से खेलना।
डेनिस ट्रब

1
@ डेनिस ट्रब आपके उत्तर के लिए धन्यवाद। इवेंट स्टोर के खिलाफ क्वेरी क्यों नहीं की जाती? मुझे डर है कि अगर हम हर बार नए बीआई मामले के साथ आते हैं तो हमें पूरी तरह से इतिहास को फिर से खेलना होगा।
मरिज हुइजेन्डवेल्ड

1
मैंने सोचा कि कुछ बिंदु पर आपको इवेंट स्टोर के अलावा टेबल भी चाहिए थे, यह नवीनतम स्थिति में मॉडल से डेटा स्टोर करने के लिए है? और यह कि आपने मॉडल को रीड मॉडल और राइट मॉडल में विभाजित किया है। लिखने का मॉडल इवेंट स्टोर के खिलाफ जाता है, और इवेंट स्टोर मार्शल मॉडल को रीड मॉडल में अपडेट करता है। रीड मॉडल में टेबल होते हैं जो आपके सिस्टम में संस्थाओं का प्रतिनिधित्व करते हैं - इसलिए आप रिपोर्टिंग और देखने के लिए रीड मॉडल का उपयोग कर सकते हैं। मुझे कुछ गलत समझा होगा।
theBoringCoder

10
@theBoringCoder ऐसा लगता है कि आपके पास इवेंट सोर्सिंग और CQRS भ्रमित है या कम से कम आपके सिर में गड़बड़ है। वे अक्सर एक साथ पाए जाते हैं लेकिन वे एक ही चीज नहीं हैं। CQRS ने आपको अपने पढ़ने और लिखने के मॉडल को अलग कर दिया है जबकि इवेंट सोर्सिंग ने आपके आवेदन में सत्य के एकल स्रोत के रूप में एक इवेंट स्ट्रीम का उपयोग किया है।
ब्रायन एंडरसन

7

GitHub प्रोजेक्ट CQRS.NET के कुछ ठोस उदाहरण हैं कि आप कुछ अलग तकनीकों में EventStores कैसे कर सकते हैं। लिखने के समय SQL में एक कार्यान्वयन है Linq2SQL और इसके साथ जाने के लिए एक SQL स्कीमा का उपयोग करते हुए , MongoDB के लिए एक है, डॉक्यूमेंटीडीबी के लिए एक (CosmosDB अगर आप Azure में हैं) और एक EventStore (जैसा कि ऊपर उल्लेख किया गया है) का उपयोग कर । एज़्योर में टेबल स्टोरेज और ब्लॉब स्टोरेज जैसे कुछ और हैं जो फ्लैट फाइल स्टोरेज के समान हैं।

मुझे लगता है कि मुख्य बिंदु यह है कि वे सभी एक ही मूल / अनुबंध के अनुरूप हैं। वे सभी जानकारी को एक ही स्थान / कंटेनर / टेबल में संग्रहीत करते हैं, वे मेटाडेटा का उपयोग एक घटना को दूसरे से पहचानने के लिए करते हैं और पूरी घटना को 'बस' के रूप में स्टोर करते हैं - जैसे कि कुछ मामलों में क्रमबद्ध तकनीकों में, जैसा कि यह था। इसलिए यदि आप किसी दस्तावेज़ डेटाबेस, संबंधपरक डेटाबेस या समतल फ़ाइल को चुनते हैं, तो इस बात पर निर्भर करता है कि किसी ईवेंट स्टोर के सभी इरादों तक पहुँचने के लिए कई अलग-अलग तरीके हैं (यह उपयोगी है यदि आप किसी भी बिंदु पर अपना मन बदलते हैं और पाते हैं कि आपको माइग्रेट या समर्थन की आवश्यकता है एक से अधिक भंडारण प्रौद्योगिकी)।

परियोजना पर एक डेवलपर के रूप में मैं हमारे द्वारा किए गए कुछ विकल्पों पर कुछ अंतर्दृष्टि साझा कर सकता हूं।

सबसे पहले हमने पाया कि (यूनीक यूयूआईडी (GUIDs के बजाय पूर्णांक के बजाय) कई कारणों से रणनीतिक कारणों से अनुक्रमिक आईडी होते हैं, इस प्रकार बस एक आईडी एक कुंजी के लिए अद्वितीय नहीं थी, इसलिए हमने अपने मुख्य आईडी कुंजी कॉलम को डेटा के साथ मिला दिया ऑब्जेक्ट प्रकार बनाने के लिए जो वास्तव में होना चाहिए (आपके आवेदन के अर्थ में) अद्वितीय कुंजी। मुझे पता है कि कुछ लोग कहते हैं कि आपको इसे स्टोर करने की आवश्यकता नहीं है, लेकिन यह इस बात पर निर्भर करेगा कि आप ग्रीनफील्ड हैं या मौजूदा सिस्टम के साथ सह-अस्तित्व में हैं।

हम स्थिरता के कारणों के लिए एक एकल कंटेनर / टेबल / संग्रह के साथ फंस गए, लेकिन हमने प्रति यूनिट / ऑब्जेक्ट के साथ एक अलग टेबल के साथ खेला। हमने अभ्यास में पाया कि या तो एप्लिकेशन को "क्रिएट" अनुमतियों की आवश्यकता थी (जो आम तौर पर बोलना एक अच्छा विचार नहीं है ... आम तौर पर, हमेशा अपवाद / बहिष्करण होते हैं) या हर बार एक नई इकाई / वस्तु अस्तित्व में आई या तैनात की गई, नई भंडारण कंटेनर / टेबल / संग्रह करने की आवश्यकता है। हमने पाया कि यह स्थानीय विकास और उत्पादन तैनाती के लिए समस्याग्रस्त होने के लिए बहुत धीमी गति से था। आप नहीं कर सकते, लेकिन यह हमारा वास्तविक अनुभव था।

याद रखने वाली एक और बात यह है कि एक्शन एक्स को होने के लिए कहने से कई अलग-अलग घटनाएं घट सकती हैं, इस प्रकार एक कमांड / इवेंट द्वारा उत्पन्न सभी घटनाओं को जानना / जो कभी उपयोगी होता है। वे विभिन्न वस्तु प्रकारों में भी हो सकते हैं जैसे खरीदारी की टोकरी में "खरीद" को धक्का देना खाते को चालू कर सकता है और घटनाओं को आग लगा सकता है। एक उपभोग्य अनुप्रयोग यह सब जानना चाह सकता है, इसलिए हमने एक सहसंबंध जोड़ा। इसका मतलब था कि एक उपभोक्ता उनके अनुरोध के परिणामस्वरूप उठाए गए सभी घटनाओं के लिए पूछ सकता है। आप स्कीमा में देखेंगे ।

विशेष रूप से एसक्यूएल के साथ, हमने पाया कि यदि सूचकांक और विभाजन पर्याप्त रूप से उपयोग नहीं किए गए थे, तो प्रदर्शन वास्तव में एक अड़चन बन गया। याद रखें कि यदि आप स्नैपशॉट का उपयोग कर रहे हैं तो घटनाओं को उल्टे क्रम में स्ट्रीम करना होगा। हमने कुछ अलग-अलग इंडेक्स आज़माए और पाया कि व्यवहार में, वास्तविक दुनिया के अनुप्रयोगों में डिबगिंग के लिए कुछ अतिरिक्त इंडेक्स की आवश्यकता थी। फिर से आप स्कीमा में देखेंगे ।

उत्पादन आधारित जांच के दौरान अन्य इन-प्रोडक्शन मेटाडेटा उपयोगी था, टाइमस्टैम्प ने हमें उस क्रम में अंतर्दृष्टि प्रदान की जिसमें घटनाओं को बनाम उठाया गया था। इसने हमें एक विशेष रूप से भारी घटना संचालित प्रणाली पर कुछ सहायता प्रदान की जिसने बड़ी मात्रा में घटनाओं को उठाया, जिससे हमें नेटवर्क जैसी चीजों के प्रदर्शन और पूरे नेटवर्क में सिस्टम वितरण के बारे में जानकारी मिली।


यह बहुत अच्छा है, धन्यवाद। जैसा कि ऐसा होता है, इस प्रश्न को लिखने के बहुत समय बाद, मैंने खुद को अपने Inforigami.Regalo लाइब्रेरी के हिस्से के रूप में गिथब पर बनाया है। RavenDB, SQL सर्वर और EventStore कार्यान्वयन। हंसी के लिए फ़ाइल-आधारित एक करने के बारे में सोचा। :)
नील बर्नवेल

1
चीयर्स। मैंने मुख्य रूप से उन अन्य लोगों के लिए उत्तर जोड़ा है जो हाल के दिनों में इसके पार आए हैं और सीखे गए कुछ पाठों को साझा करते हैं, न कि सिर्फ नतीजों के बजाय।
cdmdotnet

3

वैसे आप डेटोमिक को देखना चाहते हैं।

डाटामिक लचीले, समय-आधारित तथ्यों का एक डेटाबेस है , जो प्रश्नों को जोड़ता है और लोचदार मापनीयता और ACID लेनदेन के साथ जुड़ता है।

मैंने यहां एक विस्तृत उत्तर लिखा

आप यहां स्टुअर्ट हल्लोवे से बात कर सकते हैं, जो यहां के डैमोमिक के डिजाइन के बारे में बता रहे हैं

चूंकि समय में डेटा परमाणु स्टोर करता है, आप इसका उपयोग इवेंट सोर्सिंग उपयोग के मामलों के लिए कर सकते हैं, और बहुत कुछ।


2

मुझे लगता है कि समाधान (1 और 2) बहुत जल्दी एक समस्या बन सकता है क्योंकि आपका डोमेन मॉडल विकसित होता है। नए क्षेत्र बनाए जाते हैं, कुछ अर्थ बदल जाते हैं, और कुछ अब उपयोग नहीं किए जा सकते हैं। अंततः आपकी तालिका में दर्जनों अशक्त क्षेत्र होंगे, और घटनाओं को लोड करना गड़बड़ होगा।

यह भी याद रखें कि ईवेंट स्टोर का उपयोग केवल लिखने के लिए किया जाना चाहिए, आप केवल ईवेंट लोड करने के लिए इसे क्वेरी करते हैं, एग्रीगेट के गुणों को नहीं। वे अलग चीजें हैं (यह CQRS का सार है)।

समाधान 3 आमतौर पर लोग क्या करते हैं, इसके कई तरीके हैं जो कि प्रभावित करते हैं।

उदाहरण के लिए, SQL सर्वर के साथ उपयोग किए जाने पर EventFlow CQRS इस स्कीमा के साथ एक तालिका बनाता है:

CREATE TABLE [dbo].[EventFlow](
    [GlobalSequenceNumber] [bigint] IDENTITY(1,1) NOT NULL,
    [BatchId] [uniqueidentifier] NOT NULL,
    [AggregateId] [nvarchar](255) NOT NULL,
    [AggregateName] [nvarchar](255) NOT NULL,
    [Data] [nvarchar](max) NOT NULL,
    [Metadata] [nvarchar](max) NOT NULL,
    [AggregateSequenceNumber] [int] NOT NULL,
 CONSTRAINT [PK_EventFlow] PRIMARY KEY CLUSTERED 
(
    [GlobalSequenceNumber] ASC
)

कहाँ पे:

  • GlobalSequenceNumber : सरल वैश्विक पहचान, जब आप अपना प्रक्षेपण (रेडीमॉडल) बनाते हैं, तो गुम घटनाओं को आदेश देने या पहचानने के लिए उपयोग किया जा सकता है।
  • बैचैड : उन घटनाओं के समूह की पहचान, जहां परमाणु ( टीबीएच) डाला गया है, यह पता नहीं है कि यह उपयोगी क्यों होगा)
  • एग्रीगेटआईड : एग्रीगेट की पहचान
  • डेटा : सीरियल की घटना
  • मेटाडेटा : घटना से अन्य उपयोगी जानकारी (उदाहरण के लिए deserialize, टाइमस्टैम्प, मूल आईडी से आईडी आदि) के लिए उपयोग किया जाता है।)
  • AggregateSequenceNumber : एक ही समुच्चय के भीतर अनुक्रम संख्या (यह उपयोगी है यदि आपके पास ऑर्डर से बाहर होने वाले लेखन नहीं हो सकते हैं, तो आप इस क्षेत्र का उपयोग आशावादी संगोष्ठी के लिए करते हैं)

हालाँकि, यदि आप स्क्रैच से पैदा कर रहे हैं, तो मैं YAGNI सिद्धांत का पालन करूंगा, और आपके उपयोग के मामले के लिए न्यूनतम आवश्यक फ़ील्ड बना सकता हूं।


मेरा तर्क है कि BatchId संभवतः CorrelationId और CausationId से संबंधित हो सकता है। यह पता लगाने के लिए कि घटनाओं का क्या कारण है, और यदि आवश्यक हो तो उन्हें एक साथ स्ट्रिंग करें।
डैनियल पार्क

यह हो सकता था। हालाँकि यह ऐसा है, यह इसे अनुकूलित करने का एक तरीका प्रदान करने के लिए समझ में आता है (जैसे अनुरोध के आईडी के रूप में सेटिंग), लेकिन फ्रेमवर्क ऐसा नहीं करता है।
Fabio Marreco

1

संभावित संकेत "धीरे-धीरे बदलते आयाम" के बाद डिजाइन होता है (टाइप = 2) आपको कवर करने में मदद करनी चाहिए:

  • होने वाली घटनाओं का क्रम (सरोगेट कुंजी के माध्यम से)
  • प्रत्येक राज्य का स्थायित्व (मान्य - से मान्य)

लेफ्ट फोल्ड फ़ंक्शन को लागू करने के लिए भी ठीक होना चाहिए, लेकिन आपको भविष्य की क्वेरी जटिलता के बारे में सोचना होगा।


1

मुझे लगता है कि यह एक देर से जवाब होगा, लेकिन मैं यह बताना चाहूंगा कि अगर आपके थ्रूपुट की आवश्यकता अधिक नहीं है तो इवेंट सोर्सिंग स्टोरेज के रूप में आरडीबीएमएस का उपयोग करना पूरी तरह से संभव है। मैं आपको उदाहरण के लिए एक इवेंट-सोर्सिंग लेज़र का उदाहरण दिखाता हूँ, जिसका मैं वर्णन करता हूँ।

https://github.com/andrewkkchan/client-ledger-service उपरोक्त एक इवेंट सोर्सिंग वेब सेवा है। https://github.com/andrewkkchan/client-ledger-core-db और ऊपर मैं राज्यों की गणना करने के लिए RDBMS का उपयोग करता हूं ताकि आप RDBMS के साथ आने वाले सभी लाभों का आनंद ले सकें जैसे लेनदेन समर्थन। https://github.com/andrewkkchan/client-ledger-core-memory और मेरे पास फट से निपटने के लिए मेमोरी में प्रोसेसिंग करने वाला एक और उपभोक्ता है।

एक वास्तविक घटना की दुकान के ऊपर काफ़्का में रहता है - क्योंकि RDBMS डालने के लिए धीमा है, खासकर जब डालने का कार्य हमेशा आकर्षक होता है।

मुझे आशा है कि इस प्रश्न के लिए पहले से ही प्रदान किए गए बहुत अच्छे सैद्धांतिक उत्तरों के अलावा कोड मदद आपको एक उदाहरण देगा।


धन्यवाद। मैंने लंबे समय से SQL- आधारित कार्यान्वयन बनाया है। मुझे यकीन नहीं है कि आवेषण के लिए आरडीबीएमएस धीमा क्यों है जब तक कि आपने एक गुच्छेदार कुंजी के लिए एक अक्षम विकल्प नहीं बनाया है। परिशिष्ट-केवल ठीक होना चाहिए।
नील बर्नवेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.