प्रतिनिधि इंटरव्यू विषय

डेटा इंजीनियरिंग इंटरव्यू: आप इवेंट्स के लिए स्कीमा-कंपैटिबिलिटी रिलीज़ गेट्स कैसे डिज़ाइन करेंगे?

डेटाकठिन
Offer.cc संपादकीय टीमप्रकाशित अपडेट किया गया

प्रश्न

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

प्रॉम्प्ट और दायरा

एक ऑर्डर इवेंट कई टीमों द्वारा प्रोड्यूस और कंज्यूम किया जाता है। एक नया वर्ज़न एक वैकल्पिक (optional) फ़ील्ड जोड़ता है, एक फ़ील्ड का नाम बदलता है, और दूसरे को रिटायर करता है; कंज्यूमर एक साथ अपग्रेड नहीं हो सकते, और ऐतिहासिक संदेशों (historical messages) को फिर से चलाया (replay) जाता है। प्रस्ताव और कंपैटिबिलिटी जांच से लेकर कैनरी रोलआउट और रोलबैक तक के गेट्स डिज़ाइन करें। समझाएं कि Avro राइटर/रीडर स्कीमा, Schema Registry मोड और डेटा-गुणवत्ता जांच एक साथ कैसे काम करते हैं।

यह डेटा अनुबंधों (data contracts), स्कीमा विकास (schema evolution), स्ट्रीमिंग रोलआउट और गवर्नेंस का परीक्षण करता है। Schema Registry वर्ज़न और कंपैटिबिलिटी जांच को केंद्रीकृत करता है, लेकिन सटीक नियम Avro, JSON Schema और Protobuf में भिन्न होते हैं।

इंटरव्यूअर क्या जांच रहा है

  • क्या आप कंपैटिबिलिटी को केवल एक बूलियन मानने के बजाय backward, forward, full और transitive कंपैटिबिलिटी में अंतर करते हैं।
  • क्या आप वास्तविक राइटर/रीडर परिनियोजन (deployment) विंडो से रोलआउट क्रम प्राप्त करते हैं।
  • क्या रजिस्ट्रेशन जांच, रनटाइम स्कीमा ID, कंज्यूमर लैग और डेटा गुणवत्ता मिलकर एक रिलीज़ गेट बनाते हैं।
  • क्या आप माइग्रेशन और रोलबैक के साथ नाम बदलने (renames), डिफ़ॉल्ट, विलोपन (deletions), enums और अपरिवर्तनीय अर्थ संबंधी (semantic) परिवर्तनों को संभालते हैं।

पहले स्पष्ट करने योग्य प्रश्न

  1. क्या फॉर्मेट Avro, JSON Schema, या Protobuf है? पार्सिंग और कंपैटिबिलिटी विवरण भिन्न होते हैं।
  2. क्या कंज्यूमर रीयल-टाइम, बैच, या रीप्ले करने वाले इतिहास हैं? सबसे पुराना राइटर वर्ज़न कितने समय तक पढ़ने योग्य रहना चाहिए?
  3. कौन सा पक्ष पहले शिप करता है, और क्या विभिन्न क्षेत्रों या टीमों में लॉन्ग-टेल (long-tail) वर्ज़न हैं?
  4. क्या सब्जेक्ट्स को टीम, इवेंट प्रकार या परिवेश (environment) द्वारा समूहीकृत किया गया है? क्या कंपैटिबिलिटी वैश्विक (global) है या प्रति-सब्जेक्ट?
  5. क्या रोलबैक पुराने प्रोड्यूसर को पुनर्स्थापित करता है, रोलआउट को रोकता है, या पुराने और नए फ़ील्ड्स के दोहरे लेखन (dual-writing) की आवश्यकता होती है?

30-सेकंड का उत्तर ढांचा

मोड चुनने से पहले वर्ज़न को एक कंज्यूमर विंडो में मैप करें: पुराने संदेशों को पढ़ने वाले नए रीडर्स को backward कंपैटिबिलिटी की आवश्यकता होती है; नए संदेशों को पढ़ने वाले पुराने रीडर्स को forward कंपैटिबिलिटी की आवश्यकता होती है; दोनों दिशाएं full का सुझाव देती हैं, जबकि ट्रांजिटिव जांच बनाए रखे गए इतिहास (retained history) को कवर करती है। रजिस्ट्री गेट में प्रत्येक स्कीमा को सत्यापित करें, फिर राइटर्स से पहले रीडर्स को रोल आउट करें। नए फ़ील्ड्स को डिफ़ॉल्ट मान दें, उपनामों (aliases) या दोहरे फ़ील्ड्स के साथ नाम बदलने को माइग्रेट करें, और हटाने से पहले कंज्यूमर विंडो के समाप्त होने की प्रतीक्षा करें। रजिस्ट्रेशन अस्वीकृति, डिसेरिएलाइज़ेशन त्रुटियों, लैग, डेड लेटर्स और फ़ील्ड गुणवत्ता की निगरानी करें; विसंगति होने पर विस्तार रोकें और पुराने वर्ज़न को बनाए रखें।

चरण-दर-चरण उत्तर

1. राइटर और रीडर मैट्रिक्स को स्पष्ट करें

संदेश राइटर स्कीमा ले जाते हैं या उसका संदर्भ देते हैं; कंज्यूमर इसे अपने रीडर स्कीमा के साथ हल (resolve) करते हैं। पुराने/नए प्रोड्यूसर बनाम पुराने/नए कंज्यूमर संयोजनों का आरेख बनाएं और चिह्नित करें कि किसे काम करना चाहिए। एक रोलिंग स्ट्रीम अपग्रेड आम तौर पर नए कंज्यूमर्स से पुराने डेटा को पढ़वाता है, इससे पहले कि नए प्रोड्यूसर्स नया डेटा लिखें।

2. मोड को जोखिम से जोड़ें

Backward यह जांचता है कि क्या एक नया रीडर किसी पुराने राइटर को पढ़ सकता है। Forward यह जांचता है कि क्या कोई पुराना रीडर किसी नए राइटर को पढ़ सकता है। Full दोनों की जांच करता है। यदि कंज्यूमर कई ऐतिहासिक वर्ज़न को फिर से चलाते हैं, तो ट्रांजिटिव सेमांटिक्स का उपयोग करें या बनाए रखे गए वर्ज़न सेट का स्पष्ट रूप से परीक्षण करें। कभी भी यह न मानें कि एक रजिस्ट्री डिफ़ॉल्ट सभी फॉर्मेट्स में सार्वभौमिक है।

3. परिवर्तन के नियम परिभाषित करें

फ़ील्ड जोड़ने के लिए एक सुरक्षित डिफ़ॉल्ट की आवश्यकता होती है जिसका व्यावसायिक अर्थ सत्यापित हो। नाम बदलने के लिए, फॉर्मेट-समर्थित उपनाम (alias) का उपयोग करें या रीडर्स को माइग्रेट करने से पहले पुराने और नए फ़ील्ड्स को डुअल-राइट करें। सबसे पुराने कंज्यूमर और रीप्ले विंडो समाप्त होने के बाद ही हटाएं। नए enum मानों के लिए, परीक्षण करें कि पुराने रीडर्स अज्ञात मानों को कैसे संभालते हैं; किसी प्रकार को संकीर्ण करना या उसके अर्थ या इकाई को बदलना एक ब्रेकिंग चेंज (breaking change) है।

text
propose -> lint -> compatibility-check -> consumer-matrix-test
        -> register -> canary-producer -> observe -> expand

4. रजिस्ट्रेशन और CI/CD गेट्स बनाएं

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

5. राइटर्स से पहले रीडर्स को रोल आउट करें

पुराने स्कीमा को पढ़ने वाले नए कंज्यूमर्स का कैनरी परीक्षण करें और डिसेरिएलाइज़ेशन त्रुटियों और लैग पर नज़र रखें। फिर डुअल-राइट करें या नए प्रोड्यूसर को रिलीज़ करें। पुराने कंज्यूमर्स और फ़ील्ड्स को केवल घोषित विंडो के बाद ही रिटायर करें। लॉन्ग-टेल कंज्यूमर्स के लिए एक मालिक, वर्ज़न, समय सीमा और रीप्ले योजना की आवश्यकता होती है; "हर कोई अपग्रेड करेगा" कोई नियंत्रण तंत्र (control plane) नहीं है।

6. गुणवत्ता मापें और सुरक्षित रूप से रोलबैक करें

अज्ञात स्कीमा ID, डिसेरिएलाइज़ेशन विफलताएं, डेड-लेटर वॉल्यूम, लापता-फ़ील्ड दर, इकाई विसंगतियां, कंज्यूमर लैग, रीप्ले सफलता और रजिस्ट्रेशन अस्वीकृति को ट्रैक करें। नए प्रोड्यूसर को रोककर और अभी भी संगत राइटर को पुनर्स्थापित करके रोलबैक करें। यदि सेमांटिक्स बदल गए हैं, तो पुराने डेटा की नए अर्थ में व्याख्या करने के बजाय एक नए टॉपिक या वर्ज़न वाले सब्जेक्ट को अलग करें।

उच्च गुणवत्ता वाला नमूना उत्तर

मैं राइटर/रीडर परिनियोजन मैट्रिक्स तैयार करूंगा, सबसे पुराने प्रोड्यूसर्स, कंज्यूमर्स और रीप्ले वर्ज़न की पहचान करूंगा, और वास्तविक फॉर्मेट के लिए नियम चुनूंगा। पुराने संदेशों को पढ़ने वाला नया रीडर backward है; नए संदेशों को पढ़ने वाला पुराना रीडर forward है; दोनों दिशाओं के लिए full की आवश्यकता होती है, और बनाए रखे गए इतिहास के लिए ट्रांजिटिव जांच की आवश्यकता हो सकती है। प्रत्येक परिवर्तन लिंटिंग, एक सब्जेक्ट-स्तरीय रजिस्ट्रेशन जांच और ऐतिहासिक-नमूना डिसेरिएलाइज़ेशन से होकर गुजरता है।

रोलआउट का क्रम पहले रीडर्स और बाद में राइटर्स का है: नए कंज्यूमर्स का कैनरी रोलआउट करें, फिर प्रोड्यूसर्स को डुअल-राइट या स्विच करें, और कंज्यूमर विंडो के बाद ही पुराने फ़ील्ड्स को हटाएं। डिफ़ॉल्ट जोड़ें, उपनामों या डुअल फ़ील्ड्स के साथ नाम बदलने को माइग्रेट करें, और विलोपन और enum परिवर्तनों के लिए पुराने-क्लाइंट व्यवहार का परीक्षण करें। रजिस्ट्रेशन अस्वीकृति, डिसेरिएलाइज़ेशन त्रुटियों, लैग, डेड लेटर्स और फ़ील्ड गुणवत्ता पर नज़र रखें। विसंगति होने पर, विस्तार रोकें और पुराने स्कीमा को बनाए रखें, पुराने प्रोड्यूसर पर लौटें या सेमांटिक्स बदलने पर वर्ज़न वाले टॉपिक्स पर रूट करें। चुने गए फॉर्मेट के लिए कंपैटिबिलिटी सत्यापित की जानी चाहिए; एक उत्पाद के डिफ़ॉल्ट Avro, JSON Schema और Protobuf के लिए साझा सेमांटिक्स नहीं हैं।

सामान्य विफलता के तरीके

  • रीडर और राइटर का नाम लिए बिना "backward सक्षम करें" कहना।
  • उपनामों, डुअल राइट्स और रीप्ले की अनदेखी करते हुए, किसी फ़ील्ड का सीधे नाम बदलना या हटाना।
  • केवल रजिस्ट्रेशन की जांच करना, वास्तविक ऐतिहासिक संदेशों और पुराने कंज्यूमर्स की नहीं।
  • नए प्रोड्यूसर को पहले शिप करना और पुराने कंज्यूमर्स को तोड़ना।
  • एक वैश्विक कंपैटिबिलिटी सेटिंग को सब्जेक्ट नीति के रूप में मानना और अनुमतियों या विचलन (drift) की अनदेखी करना।
  • केवल Kafka लैग पर नज़र रखना, जबकि फ़ील्ड लॉस, यूनिट परिवर्तन, डेड लेटर्स और डिसेरिएलाइज़ेशन त्रुटियों को छोड़ देना।

फॉलो-अप प्रश्न और संदर्भ उत्तर

जोड़े गए फ़ील्ड्स में अक्सर डिफ़ॉल्ट मानों की आवश्यकता क्यों होती है?

पुराने संदेशों में फ़ील्ड नहीं होता है, इसलिए रिकॉर्ड बनाने के लिए एक नए रीडर को एक नियतात्मक (deterministic) मान की आवश्यकता होती है। डिफ़ॉल्ट को null के साथ आवश्यक डेटा दोष को छिपाने के बजाय सेमांटिक रूप से मान्य होना चाहिए।

क्या बदले गए नाम वाले फ़ील्ड को सीधे बदला जाना चाहिए?

आमतौर पर नहीं। उपनाम का उपयोग करें या पुराने और नए फ़ील्ड्स को एक साथ लिखें, रीडर्स को माइग्रेट करें, और रीप्ले विंडो के बाद ही पुराने फ़ील्ड को हटाएं।

full और full transitive के बीच जोखिम का क्या अंतर है?

Full आमतौर पर आसन्न वर्ज़न के विरुद्ध दोनों दिशाओं की जांच करता है। Full transitive बनाए रखे गए ऐतिहासिक वर्ज़न में जांच का विस्तार करता है, जिससे गेट सख्त हो जाता है और अपग्रेड लागत अधिक हो जाती है।

एक पंजीकृत स्कीमा अभी भी डेटा क्यों खो सकता है?

कंपैटिबिलिटी संरचनात्मक समाधान (structural resolution) को कवर करती है, इकाइयों, enum अर्थ, फ़ील्ड गुणवत्ता, प्राधिकरण (authorization) या डाउनस्ट्रीम SQL को नहीं। नमूना रीप्ले, गुणवत्ता नियम और रनटाइम अवलोकन जोड़ें।

आप लॉन्ग-टेल कंज्यूमर्स के लिए निकास शर्त (exit condition) कैसे निर्धारित करते हैं?

एक मालिक, वर्ज़न, अंतिम-उपभोग समय, और रीप्ले की आवश्यकता दर्ज करें; एक समय सीमा और अलर्ट सेट करें। समय सीमा से पहले माइग्रेशन की पेशकश करें, फिर कंपैटिबिलिटी को हमेशा के लिए कमजोर करने के बजाय पुराने वर्ज़न को अलग करें या अस्वीकार करें।

आपको नया सब्जेक्ट या टॉपिक कब बनाना चाहिए?

जब सेमांटिक्स, इकाइयां, जीवनचक्र या प्राधिकरण सीमाएं बदल जाती हैं ताकि कंपैटिबिलिटी संक्रमण को व्यक्त न कर सके। अलगाव गलत व्याख्या के जोखिम को कम करता है लेकिन डुअल-राइट, रीप्ले और गवर्नेंस लागत को बढ़ाता है।

सार्वजनिक स्रोत

संबंधित प्रश्न