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

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

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

प्रश्न

रिस्पॉन्स फॉर्मेट, पेजिनेशन कंसिस्टेंसी और डायग्नोस करने योग्य विफलताओं को बनाए रखते हुए Kubernetes API सर्वर को हज़ारों ऑब्जेक्ट्स के लिए LIST रिस्पॉन्स को स्ट्रीम-एन्कोड कैसे करना चाहिए?

प्रश्न और दायरा

एक क्लस्टर में हज़ारों Pods और कस्टम रिसोर्स हैं, और कंट्रोलर रीस्टार्ट के बाद पूरे LIST अनुरोध भेजते हैं। पुराना एन्कोडर पूरे items एरे को एक सन्निहित (contiguous) बफ़र में सीरियलाइज़ करता है, जिससे API-सर्वर में मेमोरी स्पाइक्स उत्पन्न होते हैं। स्ट्रीमिंग एन्कोडिंग डिज़ाइन करें और इसके JSON व Kubernetes Protobuf दायरे, limit/continue पेजिनेशन और gzip से संबंध, क्लाइंट रिकवरी, बैकप्रेशर, ऑब्ज़र्वेबिलिटी और रोलबैक स्थितियों की व्याख्या करें।

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

  • समस्या को केवल नेटवर्क बैंडविड्थ तक सीमित करने के बजाय एन्कोडिंग बफ़र में मेमोरी पीक की पहचान करना।
  • स्ट्रीमिंग एन्कोडिंग, पेजिनेशन, कम्प्रेशन और वॉच सेमांटिक्स को अलग-अलग समझना।
  • एक LIST रिस्पॉन्स के लिए JSON/Protobuf संरचना, रिसोर्स वर्ज़न और एरर सेमांटिक्स को संरक्षित रखना।
  • धीमे क्लाइंट्स, डिस्कनेक्ट्स, CPU में वृद्धि, प्रॉक्सी बफ़रिंग और पुराने क्लाइंट्स की अनुकूलता (compatibility) को संभालना।
  • पुनरुत्पादनीय (reproducible) बेंचमार्क, मेट्रिक्स, कैनरी और रोलबैक गेट्स को परिभाषित करना।

स्पष्टीकरण हेतु सवाल

  1. क्या अनुरोध नेमस्पेस-स्कोप वाला है या क्लस्टर-व्यापी? ऑब्जेक्ट का आकार, संख्या और समवर्ती (concurrent) LISTs मेमोरी बजट निर्धारित करते हैं।
  2. क्या क्लाइंट को एक पूरा रिस्पॉन्स प्राप्त करना आवश्यक है, या वह limit/continue का उपयोग कर सकता है? पेजिनेशन परिणाम के आकार को सीमित करता है लेकिन सर्वर-साइड एन्कोडिंग ऑप्टिमाइज़ेशन का स्थान नहीं लेता है।
  3. क्या पाथ में HTTP/2, gzip या रिवर्स प्रॉक्सी शामिल हैं? प्रॉक्सी बफ़रिंग एन्कोडिंग के दौरान मेमोरी रिलीज़ करने के एंड-टू-एंड लाभ को बदल देती है।
  4. क्या JSON, Kubernetes Protobuf या दोनों की आवश्यकता है? एन्कोडर कवरेज रोलआउट क्रम को बदल देता है।

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

मैं सबसे पहले मेमोरी स्पाइक का कारण पूरे items एरे को सीरियलाइज़ करने को मानूँगा, फिर एन्कोडर को वृद्धिशील (incrementally) रूप से लिखने के लिए बदलूँगा: कलेक्शन प्रीफिक्स उत्सर्जित (emit) करें, प्रत्येक आइटम को एन्कोड करके लिखें, और फिर सफिक्स उत्सर्जित करें। JSON और Kubernetes Protobuf अपने रिसोर्स सेमांटिक्स को बनाए रखते हैं; पेजिनेशन रिज़ल्ट साइज़ को नियंत्रित करता है और कम्प्रेशन बैंडविड्थ को नियंत्रित करता है। एक सीमित बफ़र और राइट बैकप्रेशर धीमे क्लाइंट्स को संभालते हैं। मैं RSS पीक, एन्कोडिंग CPU, पहले बाइट का समय (time to first byte), कम्पलीशन लेटेंसी और डिस्कनेक्ट्स को मापूँगा, पहले JSON को कैनरी करूँगा, फिर रोलआउट का विस्तार करने से पहले Protobuf, प्रॉक्सी और पुराने क्लाइंट्स को मान्य करूँगा। किसी गेट सीमा से अधिक होने पर रोलबैक ट्रिगर होगा।

गहराई से उत्तर

1. मेमोरी पीक का विश्लेषण करें

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

2. एक आइटम-दर-आइटम एन्कोडर डिज़ाइन करें

निश्चित कलेक्शन फ़ील्ड्स पहले लिखें। items खुलने के बाद, एक ऑब्जेक्ट को सीरियलाइज़ करें, उसे लिखें, और अगले को प्रोसेस करने से पहले उसके अस्थायी बफ़र को रिलीज़ करें। एक असीमित बाइट स्ट्रिंग में आइटम्स को अपेंड न करें। Kubernetes का कार्यान्वयन JSON और Protobuf कलेक्शन एन्कोडर्स को लक्षित करता है और API ऑब्जेक्ट के आकार को बदले बिना बल्क items फ़ील्ड पर ध्यान केंद्रित करता है।

text
write(listPrefix)
for item in items:
    encoded = encodeOne(item)
    writeWithBackpressure(encoded)
    release(encoded)
write(listSuffix)

स्ट्रीमिंग मेमोरी लाइफटाइम को बदलती है, ऑब्जेक्ट क्रम, मेटाडेटा, रिसोर्स वर्ज़न या एरर परिभाषाओं को नहीं। यदि कोई क्लाइंट रिस्पॉन्स के बीच में डिस्कनेक्ट हो जाता है, तो एन्कोडिंग रोकें और वर्तमान आइटम को रिलीज़ करें; आंशिक बॉडी एक सफल LIST नहीं है।

3. पेजिनेशन, कम्प्रेशन और वॉच को अलग करें

limit/continue एक कलेक्शन को सुसंगत (consistent) पेजों में विभाजित करते हैं, जिससे एक अनुरोध का आकार कम होता है और क्लाइंट्स वृद्धिशील रूप से प्रोसेस कर पाते हैं; वे टोकन समाप्ति (expiry), रीस्टार्ट और क्लाइंट लूप्स लाते हैं। जब एक पेज बड़ा होता है तब भी स्ट्रीमिंग मायने रखती है क्योंकि यह सर्वर-साइड एन्कोडिंग पीक को नियंत्रित करती है। gzip नेटवर्क बाइट्स को कम करता है, लेकिन एक कंप्रेसर बफ़रिंग जोड़ सकता है, इसलिए इसकी फ़्लश पॉलिसी को मापें। watch अलग रिकवरी सेमांटिक्स वाला एक निरंतर इवेंट स्ट्रीम है और एक सुसंगत LIST की जगह नहीं ले सकता।

4. बैकप्रेशर और प्रॉक्सी को संभालें

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

5. अनुकूलता (Compatibility), कैनरी और रोलबैक

continue, रिसोर्स वर्ज़न और एरर्स सहित JSON/Protobuf वायर संरचना और कंटेंट नेगोशिएशन को अपरिवर्तित रखें। कई ऑब्जेक्ट्स और कम समवर्तीता वाले रिसोर्स प्रकारों के लिए पहले फीचर सक्षम करें, RSS पीक, CPU, फ़र्स्ट-बाइट लेटेंसी, कम्पलीशन लेटेंसी, डिस्कनेक्ट्स और API एरर दर की तुलना करें, फिर विस्तार करें। यदि कोई पुराना प्रॉक्सी चंक्ड या कंप्रेस्ड रिस्पॉन्स स्वीकार नहीं कर सकता है, तो एक फीचर गेट बनाए रखें या क्लाइंट क्षमता के आधार पर पुराने एन्कोडर का चयन करें। केवल औसत थ्रूपुट के बजाय मेमोरी पीक, P99 लेटेंसी या एरर-रेट रिग्रेशन पर रोलबैक करें।

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

मैं समस्या को API-सर्वर एन्कोडिंग पीक तक सीमित करूँगा। मैं इसे समवर्ती LIST लोड के साथ पुनरुत्पादित करूँगा, फिर एन्कोडर से कलेक्शन प्रीफिक्स उत्सर्जित करवाऊँगा, प्रत्येक आइटम को सीरियलाइज़ और राइट करवाऊँगा, उसके अस्थायी बफ़र को रिलीज़ करूँगा और सफिक्स उत्सर्जित करूँगा। यह एन्कोडिंग-स्टेज की अस्थायी मेमोरी को कम करता है; यह ऑब्जेक्ट्स को पढ़ने, सॉर्ट करने या ऑथराइज़ करने की लागत को नहीं हटाता है। JSON और Kubernetes Protobuf अपने वायर आकार को बनाए रखते हैं, limit/continue पेजिनेशन बना रहता है, gzip बैंडविड्थ नियंत्रण बना रहता है, और watch एक अलग इवेंट कॉन्ट्रैक्ट बना रहता है। राइट्स सॉकेट बैकप्रेशर और रद्दीकरण का पालन करते हैं, और प्रॉक्सी बफ़रिंग को अलग से मापा जाता है। मैं JSON को कैनरी करूँगा, फिर Protobuf और प्रमुख प्रॉक्सी को, RSS पीक, एन्कोडिंग CPU, पहले बाइट का समय, कम्पलीशन लेटेंसी और डिस्कनेक्ट्स की तुलना करूँगा। जब रिग्रेशन बेसलाइन से अधिक हो जाता है, तो एक गेट फीचर को अक्षम कर देता है या पुराने एन्कोडर का चयन करता है। परीक्षणों में धीमे क्लाइंट्स, डिस्कनेक्ट्स, खाली सूचियां, बड़े आइटम्स, समाप्त हो चुके कंटीन्यू टोकन और पुराने क्लाइंट्स शामिल हैं।

सामान्य गलतियाँ

  • केवल पेजिनेशन जोड़ना → एक पेज अभी भी बड़ा और पूरी तरह से बफ़र हो सकता है → पेजिनेशन और आइटम स्ट्रीमिंग को एक साथ मान्य करें।
  • gzip को मेमोरी फिक्स के रूप में देखना → कम्प्रेशन बफ़र्स को बनाए रख सकता है → एन्कोडिंग, कम्प्रेशन और सॉकेट चरणों को अलग-अलग मापें।
  • HTTP/2 फ़्रेम स्प्लिटिंग को सर्वर स्ट्रीमिंग मानना → एप्लिकेशन अभी भी पूरी बॉडी का निर्माण कर सकता है → API-सर्वर हीप और राइट पाथ का निरीक्षण करें।
  • धीमे क्लाइंट्स के लिए असीमित बफ़रिंग की अनुमति देना → समवर्ती धीमे कनेक्शन्स मेमोरी को बढ़ा देते हैं → कनेक्शन्स, रद्दीकरण और बैकप्रेशर को सीमित करें।
  • LIST आकार या रिसोर्स वर्ज़न को बदलना → क्लाइंट्स और कंसिस्टेंसी सेमांटिक्स टूट जाते हैं → केवल एन्कोडिंग लाइफटाइम को बदलें और वायर रिग्रेशन चलाएं।

फ़ॉलो-अप और उत्तर

क्या होता है जब कोई क्लाइंट 3,000वें ऑब्जेक्ट के बाद डिस्कनेक्ट हो जाता है?

एन्कोडिंग संदर्भ को रद्द करें, बाद के ऑब्जेक्ट्स को पढ़ना बंद करें, वर्तमान बफ़र को रिलीज़ करें और कारण रिकॉर्ड करें। क्लाइंट आंशिक बॉडी को एक सफल LIST के रूप में नहीं मान सकता; यदि उसे पूरे सेट की आवश्यकता है तो वह मूल पेजिनेशन सीमा से पुनः प्रारंभ करता है।

यदि पेजिनेशन किसी पेज को 500 ऑब्जेक्ट्स तक सीमित करता है, तो इसे स्ट्रीम भी क्यों करें?

पांच सौ ऑब्जेक्ट्स अभी भी बड़े हो सकते हैं, विशेष रूप से कस्टम रिसोर्स। पेजिनेशन रिज़ल्ट सेट को सीमित करता है; स्ट्रीमिंग एन्कोडिंग के दौरान अस्थायी सर्वर मेमोरी को सीमित करती है। वे विभिन्न चरणों को संबोधित करते हैं और उन्हें संयोजित किया जा सकता है।

क्या डिज़ाइन विफल हो जाता है यदि कोई प्रॉक्सी फॉरवर्ड करने से पहले रिस्पॉन्स को पूरी तरह से बफ़र करता है?

सर्वर अभी भी अपने स्वयं के एन्कोडिंग पीक को कम कर सकता है, लेकिन क्लाइंट के फ़र्स्ट-बाइट और एंड-टू-एंड रिलीज़ लाभ समाप्त हो जाते हैं। प्रॉक्सी बफ़रिंग को एक डिप्लॉयमेंट पूर्व शर्त (prerequisite) के रूप में मानें, रूट द्वारा पहले बाइट के समय को रिकॉर्ड करें, और जब प्रॉक्सी स्ट्रीम न कर सके तो कैनरी को अक्षम या संकीर्ण करें।

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

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

संबंधित इंटरव्यू टूल

सिस्टम डिज़ाइन उत्तर के लिए हल करें का उपयोग करें

पहले आवश्यकताओं को स्पष्ट करें, फिर स्केल, आर्किटेक्चर, कंपोनेंट चयन और ट्रेड-ऑफ की ओर बढ़ें।

टूल देखें