प्रॉम्प्ट और लागू भूमिकाएं
एक प्रोडक्ट डेटाबेस सर्च के लिए सोर्स ऑफ ट्रुथ (source of truth) है। एक नियर-रियल-टाइम CDC पाइपलाइन डिज़ाइन करें जो सर्च इंडेक्स में इंसर्ट, अपडेट और डिलीट को विश्वसनीयता से सिंक करे। इसे प्रारंभिक स्नैपशॉट, कैच-अप, डुप्लिकेट डिलीवरी, कंज्यूमर रुकावट, स्कीमा इवोल्यूशन और इंडेक्स रीबिल्ड का समर्थन करना चाहिए। बताएं कि आप यह कैसे साबित करेंगे कि इवेंट खोते नहीं हैं और कोई पुराना इवेंट किसी नए इवेंट को ओवरराइट नहीं कर सकता है।
यह बैकएंड, डेटा-इन्फ्रास्ट्रक्चर, सर्च-प्लेटफ़ॉर्म और सिस्टम-डिज़ाइन इंटरव्यू के लिए उपयुक्त है। मान लें कि सोर्स कमिट ऑर्डर या समकक्ष लॉग पोज़ीशन प्रदर्शित कर सकता है, और सर्च इंडेक्स एक रीबिल्ड करने योग्य व्युत्पन्न (derived) सिस्टम है। Kafka, Debezium, और Elasticsearch विकल्प हैं, आवश्यकताएं नहीं; पहले सेमेंटिक्स और विफलता सीमाओं (failure boundaries) को परिभाषित करें।
इंटरव्यूअर क्या टेस्ट कर रहा है
इंटरव्यूअर यह देखना चाहता है कि क्या आप "डेटाबेस राइट कमिट हो गया" को "इंडेक्स अंततः दिखाई दे रहा है" से अलग करते हैं, जिसमें प्रत्येक चरण के लिए एक अवलोकनीय अनुबंध (observable contract) हो। एक मजबूत उत्तर इवेंट की (key), ऑपरेशन, ट्रांज़ैक्शन या लॉग पोज़ीशन, और स्कीमा वर्ज़न को परिभाषित करता है; एक असुरक्षित टाइमस्टैम्प पोल के बजाय लॉग-आधारित कैप्चर चुनता है; और स्नैपशॉट ओवरलैप, कम से कम एक बार (at-least-once) रिप्ले, प्रति-की ऑर्डरिंग, डिलीट टॉम्बस्टोन और अलियास कटओवर को संभालता है। केवल एक डेटाबेस, कतार और सर्च बॉक्स वाला आरेख चेकपॉइंट, रिप्ले और मिलान (reconciliation) नियमों के बिना विश्वसनीयता साबित नहीं कर सकता।
उत्तर देने से पहले स्पष्ट करने योग्य प्रश्न
- ताज़गी (freshness) का लक्ष्य क्या है? कमिट के पांच सेकंड बाद या मिनटों बाद? यह बफरिंग, अलर्ट और फ़ॉलबैक बजट निर्धारित करता है।
- किस प्रकार की ऑर्डरिंग की आवश्यकता है? आमतौर पर एक प्रोडक्ट को सोर्स कमिट ऑर्डर का पालन करना चाहिए; सभी प्रोडक्ट्स में ग्लोबल ऑर्डर की आवश्यकता नहीं होती है। क्रॉस-टेबल इनवेरिएंट्स के लिए एक एग्रीगेट इवेंट की आवश्यकता हो सकती है।
- क्या डिलीट हार्ड हैं या सॉफ्ट? हार्ड डिलीट के लिए टिकाऊ टॉम्बस्टोन या डिलीट इवेंट की आवश्यकता होती है; सॉफ्ट डिलीट के लिए इंडेक्स किए गए दस्तावेज़ में दृश्यता नियमों की आवश्यकता होती है।
- क्या स्नैपशॉट के दौरान राइट्स जारी रह सकते हैं? यदि हाँ, तो एक स्नैपशॉट पोज़ीशन परिभाषित करें और स्नैपशॉट विंडो को कवर करने के लिए उस पोज़ीशन के बाद के परिवर्तनों को बनाए रखें।
- स्कीमा कैसे विकसित होता है? क्या पुराने कंज्यूमर जोड़े गए फ़ील्ड को अनदेखा कर सकते हैं? क्या हटाए गए या फिर से टाइप किए गए फ़ील्ड के लिए दोहरे रीड/राइट, एक नए इवेंट वर्ज़न, या रीबिल्ड की आवश्यकता होती है?
- क्या रीबिल्ड ज़ीरो-डाउनटाइम होना चाहिए? यदि हाँ, तो एक नया इंडेक्स लिखें, एक अलियास को परमाणु रूप से (atomically) बदलें, और पुराने कंज्यूमर्स के लिए एक रिप्ले पॉइंट बनाए रखें।
30-सेकंड उत्तर फ्रेमवर्क
"मैं प्राथमिक डेटाबेस को सोर्स ऑफ ट्रुथ मानूंगा और इसके लॉग से कमिट किए गए इंसर्ट, अपडेट और डिलीट को कैप्चर करूंगा। प्रत्येक इवेंट में एक की (key), ऑपरेशन, सोर्स LSN, ट्रांज़ैक्शन ID, स्कीमा वर्ज़न और पहले/बाद के मान होते हैं। प्रारंभिक लोड अपनी लॉग पोज़ीशन रिकॉर्ड करते हुए एक सुसंगत स्नैपशॉट से शुरू होता है; उस पोज़ीशन के बाद के इवेंट उसी रिप्ले करने योग्य स्ट्रीम के माध्यम से जारी रहते हैं, और कंज्यूमर प्रोडक्ट की द्वारा आइडेम्पोटेंट रूप से लिखते हैं।
डिलीवरी कम से कम एक बार (at least once) होती है। चेकपॉइंट केवल इंडेक्स साइड इफेक्ट सफल होने के बाद आगे बढ़ता है, और डुप्लिकेट इवेंट एक की प्लस वर्ज़न या LSN शर्त द्वारा अस्वीकार कर दिए जाते हैं। रुका हुआ कंज्यूमर अपने चेकपॉइंट से फिर से शुरू होता है। मैं लैग, सबसे पुराने इवेंट की आयु, स्लॉट रिटेंशन, और डेटाबेस-टू-इंडेक्स वर्ज़न नमूनों को प्रदर्शित करूंगा। रीबिल्ड उसी स्ट्रीम को एक नए इंडेक्स में लिखता है, इसके कैच-अप होने तक प्रतीक्षा करता है, और फिर परमाणु रूप से अलियास को स्विच करता है।"
चरण-दर-चरण गहन विश्लेषण
चरण 1: इवेंट अनुबंध और कैप्चर सीमा को परिभाषित करें
लॉग-आधारित CDC कमिट किए गए डेटाबेस परिवर्तनों को पढ़ता है और सोर्स ऑर्डर या लॉग पोज़ीशन को सुरक्षित रखता है। PostgreSQL में, लॉजिकल डिकोडिंग WAL से परिवर्तनों को निकालती है, और एक रेप्लिकेशन स्लॉट एक स्ट्रीम का प्रतिनिधित्व करता है जिसे मूल क्रम में रिप्ले किया जा सकता है। एक स्लॉट आवश्यक WAL को बनाए रखता है, इसलिए स्लॉट रिटेंशन की निगरानी की जानी चाहिए; एक रुका हुआ कनेक्टर प्राइमरी की डिस्क को समाप्त कर सकता है।
प्रत्येक इवेंट में entity_id, operation, source_position, transaction_id, schema_version, before, और after शामिल होना चाहिए। ऑडिट और डीडुप्लीकेशन के लिए source_position का उपयोग करें, बिज़नेस ऑर्डर के रूप में संदेश आगमन समय का नहीं। यदि एक ट्रांज़ैक्शन कई प्रोडक्ट्स को बदलता है, तो तय करें कि क्या इंडेक्स उन्हें एक-एक करके प्रदर्शित कर सकता है या स्ट्रीम को ट्रांज़ैक्शन सीमा पर एग्रीगेट करना चाहिए।
चरण 2: स्नैपशॉट और स्ट्रीम को एक पोज़ीशन से कनेक्ट करें
खतरनाक ओवरलैप तब होता है जब स्नैपशॉट एक पुरानी पंक्ति को पढ़ रहा होता है जबकि स्ट्रीम उसी की (key) के लिए एक नया इवेंट डिलीवर करती है। स्नैपशॉट शुरू होने पर एक लॉग पोज़ीशन P0 रिकॉर्ड करें। स्नैपशॉट दस्तावेज़ शुरुआत में स्थिति का प्रतिनिधित्व करते हैं; P0 के बाद के इवेंट उपलब्ध रहते हैं और स्नैपशॉट परिणाम के बाद लागू होते हैं।
P0 = captureSourcePosition()
startStreaming(after=P0)
for row in consistentSnapshot():
indexUpsert(row, version=P0)
for event in stream:
if event.position > indexedVersion[event.key]:
applyIdempotently(event)
checkpoint(event.position) # only after index write succeedsवास्तविक कनेक्टर READ और UPDATE इवेंट के बीच टकराव को हल करने के लिए स्नैपशॉट विंडो, प्राइमरी-की चंक्स और बफर का उपयोग कर सकते हैं। एक इंटरव्यू में, बताएं कि यह एक पुरानी स्नैपशॉट पंक्ति को कमिट किए गए अपडेट को ओवरराइट करने से रोकता है; "स्नैपशॉट समाप्त होने के बाद स्ट्रीम शुरू करना" पर्याप्त नहीं है।
चरण 3: ऑर्डरिंग, आइडेम्पोटेन्स और रिकवरी को स्पष्ट करें
entity_id द्वारा पार्टीशन करें ताकि एक प्रोडक्ट के इवेंट सोर्स ऑर्डर बनाए रखें जबकि विभिन्न प्रोडक्ट समानांतर में चलें। एक बाहरी वर्ज़न, सशर्त राइट, या वर्ज़न वाले दस्तावेज़ का उपयोग करें ताकि कोई इवेंट केवल पुरानी पोज़ीशन को ही ओवरराइट कर सके। DELETE एक टॉम्बस्टोन या वर्ज़न वाला डिलीट लिखता है और देर से आने वाले UPDATE को दस्तावेज़ को पुनर्जीवित (resurrect) करने से रोकने के लिए पर्याप्त मेटाडेटा बनाए रखता है।
चेकपॉइंट का अर्थ है "इस इवेंट के लिए साइड इफेक्ट स्थायी रूप से पूरा हो गया है।" संदेश खींचने या HTTP अनुरोध भेजने के तुरंत बाद इसे कमिट न करें। इंडेक्स राइट के बाद लेकिन चेकपॉइंट से पहले क्रैश होने पर डुप्लिकेट बनता है, इसलिए लक्ष्य राइट आइडेम्पोटेंट होना चाहिए। यदि चेकपॉइंट इंडेक्स से पहले आगे बढ़ता है, तो डेटा खो जाता है; या तो एक सत्यापन योग्य कमिट सीमा परिभाषित करें या रिप्ले करने योग्य इंडेक्स कार्य प्लस मिलान (reconciliation) का उपयोग करें।
चरण 4: रिप्ले, स्कीमा इवोल्यूशन और रीबिल्ड को संभालें
प्रत्येक कंज्यूमर को एक स्वतंत्र स्लॉट या समकक्ष प्रगति दें, बजाय इसके कि कंज्यूमर एक ही सिंगल-कंज्यूमर कर्सर के लिए प्रतिस्पर्धा करें। रिप्ले से पहले, लक्ष्य इंडेक्स की वर्ज़न नीति को फ्रीज या लेबल करें, रिप्ले रेंज को सीमित करें, और सुनिश्चित करें कि पुराने इवेंट केवल पुराने वर्ज़न ही लिख सकते हैं। अनुकूलता नियम परिभाषित करें: पुराने कंज्यूमर अक्सर जोड़े गए वैकल्पिक फ़ील्ड को अनदेखा कर सकते हैं, जबकि हटाए गए या बदले गए प्रकार के फ़ील्ड के लिए एक नए इवेंट वर्ज़न, दोहरे रीड/राइट, या रीइंडेक्सिंग की आवश्यकता हो सकती है।
रीबिल्ड के लिए लाइव इंडेक्स को खाली न करें। एक नया इंडेक्स बनाएं और उसी स्नैपशॉट पोज़ीशन से तब तक रिप्ले करें जब तक कि इसकी लागू पोज़ीशन कटओवर गेट तक न पहुंच जाए। परमाणु रूप से अलियास स्विच करें और उसी स्ट्रीम का उपभोग करना जारी रखें। यदि कटओवर विफल हो जाता है, तो पुराने अलियास और नए इंडेक्स की प्रगति को बनाए रखें, सुधारें, और फिर से कैच-अप करें; एक नए शुरुआती बिंदु का अनुमान न लगाएं।
चरण 5: मेट्रिक्स और मिलान (reconciliation) के साथ विश्वसनीयता साबित करें
CDC रीड लेटेंसी, पार्टीशन बैकलॉग, सबसे पुराने इवेंट की आयु, स्लॉट WAL रिटेंशन, प्रत्येक कंज्यूमर चेकपॉइंट, इंडेक्स-राइट विफलताएं, पुनः प्रयास, डेड लेटर्स, और डेटाबेस और इंडेक्स में प्राइमरी-की नमूनों से वर्ज़न अंतर को ट्रैक करें। डिलीट के लिए उनके अपने टॉम्बस्टोन और अवशिष्ट-दस्तावेज़ काउंटर होने चाहिए।
कंज्यूमर को रोककर, डुप्लिकेट डिलीवरी, पार्टीशन में संदेशों को पुनर्व्यवस्थित करके, स्नैपशॉट के दौरान एक की को अपडेट करके, देर से डिलीट डिलीवर करके, स्कीमा बदलकर और प्राइमरी का फेलओवर करके टेस्ट करें। एक मिलान उपकरण को वर्तमान डेटाबेस वर्ज़न को फिर से पढ़ना चाहिए, एक चुनी हुई पोज़ीशन पर स्ट्रीम को रिप्ले करना चाहिए, और सबसे छोटा असंगत नमूना उत्सर्जित करना चाहिए। अकेले एक खाली कतार यह साबित नहीं करती है कि इवेंट छोड़े नहीं गए थे या इंडेक्स राइट विफल नहीं हुए थे।
उच्च गुणवत्ता वाला नमूना उत्तर
"मैं पहले अनुबंध को परिभाषित करूंगा: डेटाबेस आधिकारिक है और इंडेक्स रीबिल्ड करने योग्य है; लक्ष्य कमिट के पांच सेकंड के भीतर खोजने योग्य होना है, जिसमें प्रति प्रोडक्ट सोर्स ऑर्डर सुरक्षित है और प्रोडक्ट्स में कोई ग्लोबल ऑर्डर नहीं है। इवेंट्स में की, इंसर्ट/अपडेट/डिलीट, LSN, ट्रांज़ैक्शन ID, स्कीमा वर्ज़न, और पहले/बाद के मान होते हैं।
मैं लॉग-आधारित CDC का उपयोग करूंगा। स्नैपशॉट शुरू होने पर मैं P0 रिकॉर्ड करता हूं और P0 के बाद उपभोग करना जारी रखता हूं। स्नैपशॉट READs स्ट्रीम UPDATEs के साथ टकरा सकते हैं, इसलिए स्नैपशॉट विंडो या समकक्ष की-वर्ज़न नियम को पुराने READ को छोड़ देना चाहिए; स्नैपशॉट के बाद केवल स्ट्रीम शुरू करने से एक अंतर रह जाता है। कंज्यूमर की द्वारा पार्टीशन करते हैं और एक बाहरी वर्ज़न या सशर्त राइट का उपयोग करते हैं। डिलीट एक टॉम्बस्टोन वर्ज़न बनाए रखते हैं ताकि देर से किया गया अपडेट किसी दस्तावेज़ को पुनर्जीवित न कर सके।
चेकपॉइंट केवल इंडेक्स साइड इफेक्ट सफल होने के बाद ही आगे बढ़ता है। इसलिए क्रैश से कम से कम एक बार (at-least-once) रिप्ले होता है, जिसे लक्ष्य को आइडेम्पोटेंट रूप से सहन करना चाहिए। जब कोई कनेक्टर डाउन होता है तो मैं स्लॉट द्वारा बनाए गए WAL की निगरानी करता हूं; रिकवरी के बाद यह अंतिम सुरक्षित पोज़ीशन से फिर से शुरू होता है। रीबिल्ड के लिए मैं उसी स्ट्रीम को एक नए इंडेक्स में लिखता हूं, कैच-अप की प्रतीक्षा करता हूं, और परमाणु रूप से अलियास को स्विच करता हूं।
स्वीकृति केवल एक खाली कतार से अधिक है। मैं स्नैपशॉट के दौरान अपडेट, डुप्लिकेट और पुनर्व्यवस्था, देर से डिलीट, कंज्यूमर क्रैश, स्कीमा परिवर्तन और प्राइमरी फेलओवर इंजेक्ट करता हूं। फिर मैं डेटाबेस वर्ज़न, इंडेक्स वर्ज़न और चेकपॉइंट की तुलना की (key) के आधार पर करता हूं। मुख्य संकेत सबसे पुराने इवेंट की आयु, WAL रिटेंशन, इंडेक्स लैग, डेड लेटर्स और असंगत नमूने हैं; किसी भी अंतर को सहेजी गई लॉग पोज़ीशन से रिप्ले करने योग्य होना चाहिए।"
सामान्य गलतियां
- CDC के रूप में अपडेट टाइमस्टैम्प को पोल करना → घड़ी की सटीकता, घड़ी की चाल और लंबे ट्रांज़ैक्शन परिवर्तनों को छिपा सकते हैं → कमिट लॉग पढ़ें या एक प्रमाण योग्य कर्सर का उपयोग करें।
- स्नैपशॉट और स्ट्रीम को स्वतंत्र रूप से शुरू करना → एक पुरानी स्नैपशॉट पंक्ति एक नए इवेंट को ओवरराइट कर सकती है → P0 रिकॉर्ड करें और READ/UPDATE टकरावों को हल करें।
- इंडेक्स अनुरोध भेजने के तुरंत बाद चेकपॉइंट को आगे बढ़ाना → एक क्रैश विंडो डेटा खो देती है → केवल एक सत्यापन योग्य साइड इफेक्ट के बाद ही आगे बढ़ें।
- at-least-once को exactly-once के रूप में मानना → डुप्लिकेट अभी भी होते हैं → सशर्त वर्ज़न राइट्स और आइडेम्पोटेंट डिलीट का उपयोग करें।
- संदेश आगमन के आधार पर ऑर्डर करना → पुनः प्रयास नेटवर्क को पुनर्व्यवस्थित करते हैं → की द्वारा पार्टीशन करें और सोर्स LSN या वर्ज़न का उपयोग करें।
- वर्ज़न वाले टॉम्बस्टोन के बिना इंडेक्स से डिलीट करना → देर से किया गया अपडेट दस्तावेज़ को पुनर्जीवित करता है → डिलीट वर्ज़न मेटाडेटा बनाए रखें।
- स्वतंत्र कंज्यूमर्स के बीच एक रेप्लिकेशन स्लॉट साझा करना → एक कंज्यूमर उन परिवर्तनों का उपभोग कर सकता है जो दूसरों को कभी नहीं मिलते → प्रति कंज्यूमर एक स्लॉट या एक स्पष्ट प्रसारण परत का उपयोग करें।
- रीबिल्ड के लिए लाइव इंडेक्स को साफ़ करना → एक विफल रिप्ले एक बड़ा सर्च आउटेज बनाता है → एक नए इंडेक्स को कैच-अप करें और परमाणु रूप से अलियास को स्विच करें।
- सबूत के रूप में एक खाली कतार का उपयोग करना → छोड़े गए इवेंट या विफल राइट्स इसे खाली छोड़ सकते हैं → पोज़ीशन, वर्ज़न और प्राथमिक नमूनों का मिलान करें।
फॉलो-अप प्रश्न और उत्तर
फॉलो-अप 1: क्या कोई इंडेक्स ऐसे ट्रांज़ैक्शन को प्रदर्शित कर सकता है जो किसी प्रोडक्ट और उसकी इन्वेंट्री दोनों को एक समय में एक पंक्ति में अपडेट करता है?
हाँ, यदि व्यवसाय एक मध्यवर्ती सर्च स्थिति को स्वीकार करता है। यदि परिणामों में दोनों को एक साथ प्रतिबिंबित करना आवश्यक है, तो ट्रांज़ैक्शन सीमा को आगे ले जाएं और दस्तावेज़ को अपडेट करने से पहले एग्रीगेट करें, या एक कमिट किया गया खोजने योग्य प्रोजेक्शन बनाएं। इंडेक्स में "लगभग एक साथ" राइट्स परमाणु (atomic) नहीं होते हैं।
फॉलो-अप 2: एक लंबा आउटेज रेप्लिकेशन स्लॉट को बहुत अधिक WAL बनाए रखने पर मजबूर करता है। आप इसे कैसे नियंत्रित करते हैं?
पहले प्राइमरी को सुरक्षित रखें: अलर्ट करें, आगे के राइट्स को सीमित करें या कंज्यूमर को डिग्रेड करें, और सत्यापित करें कि स्लॉट में अभी भी एक उपयोग करने योग्य शुरुआती पोज़ीशन है। यदि स्लॉट अमान्य हो गया है, तो एक नया स्लॉट न बनाएं और निरंतरता न मान लें; छूटे हुए LSN पहले ही खो चुके हो सकते हैं। बैकअप या पूर्ण स्नैपशॉट से रीबिल्ड करें और अंतर का मिलान करें।
फॉलो-अप 3: स्ट्रीम केवल पार्टीशन के भीतर ही क्रमित (ordered) है। आप प्रोडक्ट्स में सर्च परिणामों को कैसे रैंक करते हैं?
सर्च इंडेक्स के वर्तमान वर्ज़न को पढ़ती है और उसे ग्लोबल इवेंट ऑर्डर नहीं मानना चाहिए। यदि किसी रैंकिंग फ़ील्ड को एक सुसंगत समय की आवश्यकता है, तो सोर्स कमिट टाइम प्लस एक वर्ज़न नियम का उपयोग करें, या एक एग्रीगेटर से एक स्पष्ट अस्थायी-तिरछा (temporary-skew) बजट के साथ एक स्थिर रैंक की उत्पन्न करवाएं। पार्टीशन में ग्लोबल ऑर्डर थ्रूपुट को प्रभावित करता है और इसे प्रोडक्ट इनवेरिएंट द्वारा उचित ठहराया जाना चाहिए।
फॉलो-अप 4: जब कोई स्कीमा फ़ील्ड हटा दिया जाता है तो पुराने इंडेक्स का क्या होता है?
पहले उन कंज्यूमर्स को डिप्लॉय करें जो दोनों इवेंट वर्ज़न पढ़ सकते हैं, फिर पुराने फ़ील्ड का उत्पादन बंद करें, पुष्टि करें कि बैकलॉग और रिप्ले विंडो साफ़ हैं, और अंत में मैपिंग को माइग्रेट करें या रीबिल्ड करें। यदि फ़ील्ड प्राधिकरण या विश्लेषणात्मक अर्थ को बदलता है, तो केवल JSON प्रॉपर्टी को हटाना अपर्याप्त है; वर्ज़न वाले इवेंट और एक रोलबैक पथ बनाए रखें।