इवेंट स्टोर के बजाय "स्नैपशॉट" प्रोजेक्शन से रिहाइड्रेटिंग एग्रीगेट्स


14

इसलिए मैं कुछ समय के लिए इवेंट सोर्सिंग और सीक्यूआरएस के साथ छेड़खानी कर रहा हूं, हालांकि मुझे कभी भी वास्तविक प्रोजेक्ट पर पैटर्न लागू करने का अवसर नहीं मिला।

मैं आपके पढ़ने और लिखने की चिंताओं को अलग करने के लाभों को समझता हूं, और मैं इस बात की सराहना करता हूं कि इवेंट सोर्सिंग से "रीड मॉडल" डेटाबेस में राज्य परिवर्तनों को प्रोजेक्ट करना आसान हो जाता है जो आपके इवेंट स्टोर से अलग हैं।

मैं सुपर स्पष्ट नहीं हूं कि आप कभी भी इवेंट स्टोर से अपने एग्रीगेट को पुनर्जन्म नहीं देंगे।

यदि डेटाबेस को "पढ़ने" के लिए परिवर्तन करना इतना आसान है, तो हमेशा "राइट" डेटाबेस में परिवर्तन क्यों नहीं किया जाता है, जिसका स्कीमा आपके डोमेन मॉडल से पूरी तरह मेल खाता है? यह प्रभावी रूप से एक स्नैपशॉट डेटाबेस होगा।

मुझे लगता है कि यह जंगली में ES + CQRS अनुप्रयोगों में बहुत आम होना चाहिए।

यदि यह स्थिति है, तो स्कीमा परिवर्तन के परिणामस्वरूप आपके "राइट" डेटाबेस का पुनर्निर्माण करते समय ईवेंट स्टोर केवल उपयोगी है? या मुझे कुछ बड़ा याद आ रहा है?


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

जब तक आप घटनाओं की डिलीवरी की गारंटी दे सकते हैं। ऐसा करने के लिए, आपके एप्लिकेशन को बस एक घटना को एक टिकाऊ इवेंट बस पर प्रकाशित करना होगा। प्रकाशन के बाद, आवेदन का काम पूरा हो गया है। तब बस इसे विभिन्न ईवेंट हैंडलर्स को वितरित करेगी: एक ईवेंट स्टोर को अपडेट करने के लिए, एक स्टेट स्टोर को अपडेट करने के लिए, और किसी अन्य को रीड स्टोर्स को अपडेट करने के लिए आवश्यक है। इवेंट सोर्सिंग का उपयोग करने का कारण यह है कि आप तत्काल निरंतरता की परवाह नहीं करते हैं। इसे गले लगाने।
एंड्रयू लार्सन

कोई कारण नहीं है कि आपको इवेंट स्टोर से लगातार अपनी संस्थाओं को लोड करना चाहिए। वह इसका उद्देश्य नहीं है। इसका उद्देश्य सिस्टम में उत्पन्न होने वाली हर चीज का एक कच्चा, स्थायी लेज़र प्रदान करना है। एंटिटी स्टेट स्टोर और डिनरलाइज्ड रीड मॉडल लोडिंग और रीडिंग के लिए हैं।
एंड्रयू लार्सन

जवाबों:


14

मैं सुपर स्पष्ट नहीं हूं कि आप कभी भी इवेंट स्टोर से अपने एग्रीगेट को पुनर्जन्म नहीं देंगे।

क्योंकि "ईवेंट" रिकॉर्ड की पुस्तक हैं।

यदि डेटाबेस को "पढ़ने" के लिए परिवर्तन करना इतना आसान है, तो हमेशा "राइट" डेटाबेस में परिवर्तन क्यों नहीं किया जाता है, जिसका स्कीमा आपके डोमेन मॉडल से पूरी तरह मेल खाता है? यह प्रभावी रूप से एक स्नैपशॉट डेटाबेस होगा।

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

यदि यह स्थिति है, तो स्कीमा परिवर्तन के परिणामस्वरूप आपके "राइट" डेटाबेस का पुनर्निर्माण करते समय ईवेंट स्टोर केवल उपयोगी है? या मुझे कुछ बड़ा याद आ रहा है?

आपको कुछ बड़ा याद आ रहा है।

पहला बिंदु यह है कि यदि आप किसी घटना के समाधान पर विचार कर रहे हैं, तो ऐसा इसलिए है क्योंकि आप उम्मीद करते हैं कि जो हुआ है उसके इतिहास को संरक्षित करने में मूल्य होना चाहिए, जो यह कहना है कि आप गैर विनाशकारी परिवर्तन करना चाहते हैं

इसलिए हम इवेंट स्टोर पर लिख रहे हैं।

विशेष रूप से, इसका मतलब है कि हर बदलाव को इवेंट स्टोर पर लिखा जाना चाहिए।

प्रतिस्पर्धा करने वाले लेखक संभावित रूप से या तो एक-दूसरे के लेखन को नष्ट कर सकते हैं, या सिस्टम को अनजाने राज्य में चला सकते हैं, अगर उन्हें एक-दूसरे के संपादन की जानकारी नहीं है। तो सामान्य दृष्टिकोण जब आपको निरंतरता की आवश्यकता होती है, तो अपने लेखन को पत्रिका में एक विशिष्ट स्थिति (HTTP एपीआई में एक सशर्त पीयूटी के अनुरूप) को संबोधित करना है। एक असफल लेखन लेखक को बताता है कि पत्रिका की उनकी वर्तमान समझ सिंक से बाहर है, और उन्हें ठीक होना चाहिए।

एक ज्ञात अच्छी स्थिति पर लौटना फिर उस बिंदु से किसी भी अतिरिक्त घटनाओं को फिर से खेलना एक सामान्य वसूली रणनीति है। यह ज्ञात अच्छी स्थिति स्थानीय कैश में क्या है, या आपके स्नैपशॉट स्टोर में एक प्रतिनिधित्व की एक प्रति हो सकती है।

खुशहाल रास्ते में, आप मेमोरी में एग्रीगेट का एक स्नैपशॉट रख सकते हैं; जब कोई स्थानीय प्रति उपलब्ध न हो तो आपको केवल एक बाहरी स्टोर तक पहुंचने की आवश्यकता है।

इसके अलावा, आपको पूरी तरह से पकड़े जाने की आवश्यकता नहीं है , यदि आपके पास रिकॉर्ड की पुस्तक तक पहुंच है।

तो सामान्य दृष्टिकोण ( यदि एक स्नैपशॉट रिपॉजिटरी का उपयोग करके) इसे अतुल्यकालिक रूप से बनाए रखना है । इस तरह, यदि आपको पुनर्प्राप्त करने की आवश्यकता है, तो आप समग्र के पूरे इतिहास को फिर से लोड किए बिना और पुनरावृत्ति किए बिना ऐसा कर सकते हैं।

ऐसे कई मामले हैं जहां यह जटिलता रूचि की नहीं है, क्योंकि स्कोप किए गए जीवनकाल के साथ बारीक दाने वाले समुच्चय आमतौर पर स्नैपशॉट कैश को बनाए रखने की लागतों को पार करने के लाभों के लिए पर्याप्त घटनाओं को एकत्र नहीं करते हैं।

लेकिन जब यह समस्या के लिए सही उपकरण है, तो लेखन मॉडल में कुल का एक बासी प्रतिनिधित्व लोड करना, फिर इसे अतिरिक्त घटनाओं के साथ अद्यतन करना, पूरी तरह से उचित काम है।


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

6

चूँकि आप यह नहीं निर्दिष्ट करते हैं कि "लिखना" डेटाबेस का उद्देश्य क्या होगा, मैं यहाँ यह मानूँगा कि आपका क्या मतलब है: जब आप किसी नए अद्यतन को रजिस्टर करते हैं, तो इवेंट स्टोर से कुल के पुनर्निर्माण के बजाय, आप इसे "राइट" डेटाबेस से उठाएं, परिवर्तन को मान्य करें, और एक ईवेंट जारी करें।

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

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

आम तौर पर, सिस्टम इस तरह काम करेगा:

1. Request to book seat #1
2. Check in the "already booked" list: the list is empty.
3. Issue a "booked seat #1" event.
4. Projection process catches the event, adds seat #1 to the "already booked" list.
5. Another request to book seat #1.
6. Check in the list: the list contains seat #1
7. Respond with an error message.

हालाँकि, क्या होगा यदि अनुरोध बहुत जल्दी आते हैं, और चरण 4 से पहले चरण 5 होता है?

1. Request to book seat #1
2. Check in the "already booked" list: the list is empty.
3. Issue a "booked seat #1" event.
4. Another request to book seat #1.
5. Check in the list: the list is still empty.
6. Issue another "booked seat #1" event.

अब आपके पास एक ही सीट बुक करने के लिए दो इवेंट हैं। सिस्टम स्थिति दूषित है।

ऐसा होने से रोकने के लिए, आपको किसी प्रक्षेपण के विरुद्ध अद्यतनों को मान्य नहीं करना चाहिए। किसी अद्यतन को मान्य करने के लिए, आप इवेंट स्टोर से कुल का पुनर्निर्माण करते हैं, फिर इसके विरुद्ध अद्यतन को मान्य करते हैं। उसके बाद, आप एक ईवेंट जारी करते हैं, लेकिन यह सुनिश्चित करने के लिए टाइमस्टैम्प गार्ड का उपयोग करते हैं कि स्टोर से अंतिम बार पढ़ने के बाद कोई नई ईवेंट जारी नहीं की गई है। यदि यह विफल रहता है, तो आप अभी पुनः प्रयास करें।

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


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

इसलिए, मेरे पास मेरी निरंतरता के मुद्दे थे। हालांकि, मैंने मान लिया कि यह स्केलेबिलिटी की कीमत पर था।
मेटाफ़ाइट

लिखने वाले डेटाबेस में समकालिक रूप से लिखना अभी भी भ्रष्टाचार का खतरा बना हुआ है: यदि आपका लेखन इवेंट स्टोर में सफल होता है, तो क्या होता है, लेकिन लेखन डेटाबेस में आपका लेखन विफल हो जाता है?
फ्योदोर सोइकिन

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

1
कोई डेटा कभी नहीं खोता है, यह बड़ा बिंदु है। डेटा थोड़ी देर के लिए असुविधाजनक (पढ़ने के लिए) आकार में फंस सकता है, लेकिन यह कभी नहीं खोता है।
फ्योदोर सोइकिन

3

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

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


जब मेरा एग्रीगेट स्कीमा बदलता है, तो क्या अपडेटेड "राइट" डेटाबेस बनाने के लिए मेरी घटनाओं को फिर से खेलना एक साधारण बात नहीं होगी?
मेटाफाइट

समस्या उस बदलाव का पता लगा रही है। एक एग्रीगेट बहुत बड़ी हो सकती है, जिसमें कई फाइलें / कक्षाएं होती हैं।
कांस्टेंटिन गैलबेनु

मुझे समझ नहीं आ रहा है। परिवर्तन एक सॉफ्टवेयर रिलीज के साथ होगा। रिलीज शायद "राइट" डेटाबेस को पुनर्जीवित करने के लिए एक डेटाबेस स्क्रिप्ट के साथ आएगी।
मेटाफाइट

माइग्रेशन स्क्रिप्ट के लिए यह बहुत काम है। जबकि यह चलाता है एप्लिकेशन नीचे होना चाहिए।
कांस्टेंटिन गैलबेनु

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