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

बैकएंड इंटरव्यू: आप एक बाउंडेड वर्कर पूल (Bounded Worker Pool) कैसे डिज़ाइन करेंगे?

बैकएंडमध्यम
Offer.cc संपादकीय टीमप्रकाशित अपडेट किया गया

प्रश्न

बैकएंड सेवा के लिए एक बाउंडेड वर्कर पूल डिज़ाइन करें। कतार क्षमता (queue capacity), प्रवेश या अस्वीकृति (admission or rejection), रद्दीकरण, पुनः प्रयास का स्वामित्व, परिणाम सहसंबंध (result correlation), मेट्रिक्स और ग्रेसफुल शटडाउन की व्याख्या करें।

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

एक बैकएंड सेवा के लिए एक वर्कर पूल डिज़ाइन करें जो कार्यों को स्वीकार करता है, एक साथ अधिकतम एक निश्चित संख्या में चलाता है, और स्वीकृत कार्य को चुपचाप छोड़े बिना बंद (shut down) हो जाता है। कतार क्षमता, प्रवेश या अस्वीकृति, रद्दीकरण, पुनः प्रयास का स्वामित्व, परिणाम सहसंबंध, मेट्रिक्स और ग्रेसफुल शटडाउन की व्याख्या करें।

मान लें कि कार्य स्वतंत्र हैं और डाउनस्ट्रीम API को कॉल कर सकते हैं। यह पूल एक इन-प्रोसेस (in-process) घटक है; जब कार्यों को प्रोसेस के क्रैश होने के बाद भी जीवित रहना आवश्यक हो, तो टिकाऊ कतारें (durable queues) एक अलग डिज़ाइन का हिस्सा होती हैं।

साक्षात्कारकर्ता क्या परख रहा है

वे एक स्पष्ट कंकरेंसी सीमा, एक बाउंडेड मेमोरी मॉडल और ओवरलोड के लिए एक नीति देखना चाहते हैं। वे यह भी परीक्षण करते हैं कि क्या रद्दीकरण वर्कर्स तक पहुँचता है, क्या पुनः प्रयास लोड को कई गुना बढ़ा सकते हैं, और क्या शटडाउन कतारबद्ध (queued), चल रहे (running), पूर्ण (completed) और अस्वीकृत (rejected) कार्यों में अंतर करता है।

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

  • क्या प्रोसेस क्रैश होने पर कार्य का नष्ट होना स्वीकार्य है? यदि नहीं, तो पहले कार्य को एक ड्यूरेबल ब्रोकर में रखें।
  • क्या कार्य इडेम्पोटेंट (idempotent) हैं, और क्या उन्हें सुरक्षित रूप से पुनः प्रयास किया जा सकता है?
  • डाउनस्ट्रीम दर सीमाएँ (rate limits), औसत रनटाइम और टेल लेटेंसी लक्ष्य क्या हैं?
  • कतार भर जाने पर क्या सबमिट को थोड़ी देर के लिए ब्लॉक होना चाहिए, 429 वापस करना चाहिए, या कम प्राथमिकता वाले कार्य को छोड़ देना (shed) चाहिए?
  • क्या रद्दीकरण का अर्थ केवल "शुरू होने से पहले रोकना" है, या कार्य सहयोगात्मक रूप से I/O को बाधित कर सकता है?

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

"मैं एक निश्चित वर्कर संख्या और एक सीमित कतार द्वारा समर्थित एक बाउंडेड सबमिट API प्रस्तुत करूँगा। क्षमता समाप्त होने पर प्रवेश एक स्पष्ट ओवरलोड परिणाम लौटाता है, जबकि एक संदर्भ (context) या रद्दीकरण टोकन कतारबद्ध कार्यों को निष्पादन से पहले छोड़ने की अनुमति देता है और चल रहे कार्यों को सहयोगात्मक रूप से रुकने देता है। प्रत्येक स्वीकृत कार्य का एक ID और अंतिम अवस्था (terminal state) होती है; पुनः प्रयास सीमित, जिटर (jitter) युक्त और एक ही परत द्वारा नियंत्रित होते हैं। मेट्रिक्स में कतार की गहराई, आयु, सक्रिय वर्कर्स, अस्वीकृति, रनटाइम और रद्दीकरण शामिल हैं। शटडाउन प्रवेश को रोकता है, नीति के अनुसार कतारबद्ध कार्य को रद्द करता है, एक समय सीमा (deadline) तक स्वीकृत कार्य को खाली (drain) करता है, और जो कुछ भी समाप्त नहीं हो सका उसकी रिपोर्ट करता है।"

चरण-दर-चरण गहन विश्लेषण

चरण 1: स्टेट मशीन को परिभाषित करें

submitted → queued → running → succeeded|failed|cancelled का उपयोग करें। एक भरी हुई कतार एक अदृश्य प्रतीक्षा के बजाय rejected देती है। जब कॉलर्स को क्रैश के बाद रिकवरी की आवश्यकता होती है, तो इन अवस्थाओं को प्रोसेस के बाहर बनाए रखना आवश्यक होता है।

चरण 2: वर्कर्स और कतार दोनों को सीमित करें

W वर्कर्स और कतार क्षमता Q चुनें; मेमोरी Q जॉब पेलोड और वर्कर स्टैक्स द्वारा बाउंडेड होती है। प्रति अनुरोध एक थ्रेड या goroutine न बनाएं। Python का ThreadPoolExecutor max_workers को उजागर करता है, लेकिन जब सबमिशन वॉल्यूम असीमित हो तो एप्लिकेशन-स्तरीय बाउंडेड प्रवेश नीति की अभी भी आवश्यकता होती है।

चरण 3: प्रवेश और बैकप्रेशर चुनें

नॉन-ब्लॉकिंग सबमिट, बाउंडेड वेटिंग, या प्राथमिकता-आधारित अस्वीकृति की पेशकश करें। एक स्थिर ओवरलोड कोड और Retry-After केवल तभी लौटाएं जब पुनः प्रयास करना सुरक्षित हो। एक प्रोड्यूसर जो पूरी तरह भरी कतार पर हमेशा के लिए प्रतीक्षा करता है, वह अनुरोध पथ को डेडलॉक कर सकता है, जबकि एक अनबाउंडेड कतार ओवरलोड को लेटेंसी और मेमोरी वृद्धि में बदल देती है।

text
submit(job, deadline):
    if stopping or deadline expired: return REJECTED
    if queue.try_push(job): return ACCEPTED(job.id)
    if policy == WAIT and wait_until(deadline) and queue.try_push(job):
        return ACCEPTED(job.id)
    return OVERLOADED

चरण 4: रद्दीकरण को सहयोगात्मक (cooperative) बनाएं

प्रत्येक कार्य को एक रद्दीकरण संदर्भ पास करें। उन रद्द किए गए कार्यों को हटा दें जो शुरू नहीं हुए हैं; चल रहे कार्यों को सुरक्षित बिंदुओं पर रद्दीकरण की जांच करनी चाहिए और इसे डाउनस्ट्रीम क्लाइंट्स को पास करना चाहिए। एक पूल मनमाने थ्रेड्स को सुरक्षित रूप से समाप्त (kill) नहीं कर सकता है, इसलिए गैर-बाधा डालने योग्य I/O के लिए "रद्द" का क्या अर्थ है, इसे स्पष्ट रूप से प्रलेखित करें।

चरण 5: पुनः प्रयास का स्वामित्व एकल-स्तरीय रखें

पुनः प्रयास शेड्यूल करने के लिए या तो पूल, जॉब हैंडलर, या ड्यूरेबल कतार में से किसी एक को चुनें। प्रयासों को सीमित करें, जिटर के साथ एक्सपोनेंशियल बैकऑफ़ जोड़ें, और त्रुटियों को पुनः प्रयास योग्य और स्थायी में वर्गीकृत करें। अन्यथा तीन परतों पर टाइमआउट एक ही निर्भरता के खिलाफ एक पुनः प्रयास का तूफान (retry storm) पैदा कर सकता है।

चरण 6: परिणाम और त्रुटियों को सहसंबंधित करें

एक जॉब ID या future लौटाएं, कभी भी साझा किया गया म्यूटेबल परिणाम स्लॉट नहीं। मूल त्रुटि, प्रयास गणना और अंतिम अवस्था को रिकॉर्ड करें। यदि कॉलर्स पोल करते हैं, तो परिणाम स्टोर के प्रतिधारण (retention) और प्राधिकरण को स्पष्ट करें; यदि कॉलर्स प्रतीक्षा (await) करते हैं, तो परिभाषित करें कि डिस्कनेक्ट होने से कार्य पर क्या प्रभाव पड़ता है।

चरण 7: ग्रेसफुल शटडाउन डिज़ाइन करें

शटडाउन पर, पहले प्रवेश रोकें, फिर नीति के अनुसार कतारबद्ध कार्यों को चिह्नित करें, और चल रहे कार्यों को समय सीमा तक समाप्त होने दें। Go पाइपलाइन मार्गदर्शन done सिग्नल के माध्यम से रद्दीकरण का प्रसार करता है; यही सिद्धांत यहाँ लागू होता है। समय सीमा के बाद, पुनः चलाने के लिए अधूरे कार्यों की रिपोर्ट करें या केवल एक स्पष्ट अनुबंध के साथ उन्हें परित्यक्त (abandoned) के रूप में चिह्नित करें।

चरण 8: बाधा (bottleneck) का मापन करें

कतार की गहराई और आयु, सक्रिय वर्कर्स, उपयोग (utilization), स्वीकृत/अस्वीकृत/रद्द गणना, निष्पादन अवधि, पुनः प्रयास गणना और डाउनस्ट्रीम त्रुटियों को ट्रैक करें। केवल CPU पर ही नहीं, बल्कि लगातार कतार आयु और अस्वीकृति पर भी अलर्ट सेट करें। डाउनस्ट्रीम बाधा से W का आकार तय करें: कनेक्शन पूल, बाहरी दर सीमा, या CPU क्षमता।

ट्रेड-ऑफ़ और सीमाएं

ट्रेड-ऑफ़ 1: निश्चित वर्कर्स या गतिशील स्केलिंग

निश्चित वर्कर्स कंकरेंसी को पूर्वानुमेय बनाते हैं और निर्भरताओं की रक्षा करते हैं। गतिशील स्केलिंग थ्रूपुट में सुधार कर सकती है लेकिन इसे एक कठोर वैश्विक सीमा लागू करनी चाहिए और प्रत्येक प्रतिकृति (replica) का हिसाब रखना चाहिए; अन्यथा प्रत्येक इंस्टेंस स्वतंत्र रूप से स्केल करता है और निर्भरता पर अत्यधिक भार डालता है।

ट्रेड-ऑफ़ 2: पूर्ण होने पर अस्वीकार करना या प्रतीक्षा करना

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

ट्रेड-ऑफ़ 3: इन-प्रोसेस या ड्यूरेबल कतार

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

विफलता अभ्यास (Failure drills) और विकास योजना

अभ्यास 1: डाउनस्ट्रीम आउटेज

प्रत्येक कार्य को धीरे-धीरे विफल करें और कतार की आयु, अस्वीकृति, टाइमआउट और सीमित पुनः प्रयासों को सत्यापित करें। पुष्टि करें कि जब निर्भरता अस्वस्थ हो, तो पूल अधिक कंकरेंसी नहीं बनाता है।

अभ्यास 2: रद्दीकरण का तूफान

10,000 कार्य सबमिट करें, निष्पादन से पहले आधे रद्द करें, और ड्रेन के दौरान सेवा को रोकें। सत्यापित करें कि कतारबद्ध रद्दीकरण निष्पादित नहीं होते हैं और स्वीकृत चल रहे कार्य एक रिपोर्ट की गई अंतिम स्थिति तक पहुँचते हैं।

अभ्यास 3: प्रतिकृति रोलआउट

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

सामान्य गलतियाँ और फॉलो-अप

गलती 1: अनबाउंडेड बफरिंग

एक अनबाउंडेड कतार ओवरलोड को तब तक छुपाती है जब तक मेमोरी या लेटेंसी पूरी तरह चरमरा न जाए। क्षमता और अस्वीकृति नीति को देखने योग्य (observable) बनाएं।

गलती 2: डुप्लिकेट पुनः प्रयास

यदि HTTP क्लाइंट और जॉब हैंडलर दोनों पुनः प्रयास करते हैं, तो प्रयास कई गुना बढ़ जाते हैं। एक पुनः प्रयास स्वामी असाइन करें और प्रयास मेटाडेटा को आगे प्रसारित करें।

गलती 3: रद्दीकरण को थ्रेड किलिंग समझना

अधिकांश रनटाइम मनमाने काम को सुरक्षित रूप से समाप्त नहीं कर सकते हैं। सहयोगात्मक जांच, रद्द करने योग्य I/O, और एक स्पष्ट परित्यक्त-कार्य नीति का उपयोग करें।

गलती 4: प्रवेश रोके बिना कार्य खाली करना (draining)

नए कार्य कतार को हमेशा के लिए गैर-खाली रख सकते हैं। ड्रेन समय सीमा की प्रतीक्षा करने से पहले प्रवेश बंद कर दें।

गलती 5: प्रति-प्रतिकृति सीमाओं का अभाव

10 प्रतिकृतियों पर 20 वर्कर्स का एक पूल 200 समवर्ती कॉल्स हैं। बताएं कि क्या सीमा स्थानीय, शार्डेड (sharded), या विश्व स्तर पर समन्वित है।

गलती 6: कोई परिणाम प्रतिधारण नीति न होना

फ्यूचर्स और पोलिंग रिकॉर्ड को समाप्ति (expiry), प्राधिकरण और एक विफलता पथ की आवश्यकता होती है। अन्यथा स्वीकृत कार्य असीमित स्टोरेज में बदल जाते हैं।

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

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