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

आप डेडलॉक्स (Deadlocks) को कैसे रोकते (Prevent), पहचानते (Detect), और उनसे रिकवर (Recover) करते हैं?

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

प्रश्न

एक ट्रांसफर सेवा कभी-कभार फ्रीज हो जाती है: थ्रेड A अकाउंट 42 का लॉक रखती है और अकाउंट 84 का इंतज़ार करती है, जबकि थ्रेड B अकाउंट 84 का लॉक रखती है और अकाउंट 42 का इंतज़ार करती है। क्या यह डेडलॉक है? चार आवश्यक शर्तों की व्याख्या करें और प्रिवेंशन (prevention), डिटेक्शन (detection), रिकवरी (recovery), और वैलिडेशन (validation) का डिज़ाइन तैयार करें।

प्रॉम्प्ट और लागू होने वाला संदर्भ

एक ट्रांसफर सेवा कभी-कभार फ्रीज हो जाती है: थ्रेड A अकाउंट 42 का लॉक रखती है और अकाउंट 84 का इंतज़ार करती है, जबकि थ्रेड B अकाउंट 84 का लॉक रखती है और अकाउंट 42 का इंतज़ार करती है। कोई भी थ्रेड अपना पहला लॉक नहीं छोड़ती है। क्या यह डेडलॉक है? चार आवश्यक शर्तों की व्याख्या करें और प्रिवेंशन (prevention), डिटेक्शन (detection), रिकवरी (recovery), और वैलिडेशन (validation) का डिज़ाइन तैयार करें।

यह बैकएंड, सिस्टम्स, इंफ्रास्ट्रक्चर, SRE और अन्य भूमिकाओं के लिए एक सामान्य सॉफ्टवेयर-इंजीनियरिंग और ऑपरेटिंग-सिस्टम प्रश्न है जो समवर्ती (concurrent) कोड लिखते हैं। वर्तमान अंग्रेजी और चीनी 2026 साक्षात्कार सामग्री अभी भी परिभाषा, चार आवश्यक शर्तों और हैंडलिंग रणनीतियों के बारे में अलग से पूछती है। यह लेख किसी कंपनी का उल्लेख नहीं करता है और साक्षात्कार की अप्रमाणित आवृत्ति का दावा नहीं करता है।

अकाउंट 42 और 84 काल्पनिक पहचानकर्ता हैं। कार्य केवल चार नामों को रटने से कहीं आगे जाता है। एक सशक्त उत्तर एक लंबे इंतज़ार और एक कभी न खत्म होने वाले (irreducible) वेट साइकल के बीच अंतर स्पष्ट करता है, फिर सिद्धांत को लॉक प्रोटोकॉल, रनटाइम साक्ष्य, विफलता रिकवरी और परीक्षण से जोड़ता है। प्राथमिक दायरा सिंगल-इंस्टेंस म्यूटेक्स (mutexes) और डेटाबेस रो लॉक्स (row locks) हैं। डिस्ट्रीब्यूटेड लीज (Distributed leases), नेटवर्क विभाजन (network partitions), और सर्वसम्मति (consensus) पहले उत्तर के दायरे से बाहर हैं।

साक्षात्कारकर्ता क्या मूल्यांकन करता है

पहला संकेत यह है कि क्या निदान वेट रिलेशंस (wait relationships) का उपयोग करता है। कम CPU उपयोग, टाइम-आउट अनुरोध, या दो ब्लॉक किए गए थ्रेड्स प्रगति की कमी को दर्शाते हैं लेकिन स्वतंत्र रूप से डेडलॉक साबित नहीं करते हैं। एक सशक्त उत्तर एक wait-for graph बनाता है जिसके नोड्स थ्रेड्स या ट्रांज़ैक्शन होते हैं और जिसके किनारों (edges) का अर्थ होता है "स्वामित्व वाले संसाधन की प्रतीक्षा करता है", फिर एक साइकल की तलाश करता है।

दूसरा संकेत चार आवश्यक शर्तों का सटीक उपयोग है: पारस्परिक अपवर्जन (mutual exclusion), होल्ड एंड वेट (hold and wait), कोई प्रीमेप्शन नहीं (no preemption), और सर्कुलर वेट (circular wait)। वे बताते हैं कि डेडलॉक क्यों संभव है। ट्रांसफर पाथ पर प्रत्येक को मैप किए बिना केवल उन्हें सूचीबद्ध करना एक रटा-रटाया उत्तर ही माना जाएगा।

तीसरा संकेत एक सिद्ध करने योग्य वैश्विक अपरिवर्तनीय (provable global invariant) के साथ एक प्रिवेंशन रणनीति है। व्यावहारिक विकल्प अक्सर प्रत्येक लॉक के लिए एक स्थिर कुल क्रम (stable total order) होता है, जो हर एंट्री पॉइंट पर लागू होता है। एक फ़ंक्शन में दो पंक्तियों की अदला-बदली करना अपर्याप्त है। बैच जॉब्स, रिफंड्स, रिपेयर टूल्स और भविष्य के पाथ साइकल को फिर से बना सकते हैं यदि कोई भी उल्टे क्रम में लॉक प्राप्त करता है।

अंत में, साक्षात्कारकर्ता रिकवरी सीमाओं का मूल्यांकन करता है। एक डेटाबेस एक साइकल का पता लगा सकता है और एक ट्रांज़ैक्शन को रोल बैक कर सकता है। एक इन-प्रोसेस म्यूटेक्स को आमतौर पर सुरक्षित रूप से छीना नहीं जा सकता है और निष्पादन फिर से शुरू नहीं किया जा सकता है क्योंकि बाधित कोड ने एक इनवेरिएंट का केवल आधा हिस्सा ही बदला हो सकता है। एक सशक्त उत्तर प्रिवेंशन (prevention), अवॉइडेंस (avoidance), डिटेक्शन (detection), और रिकवरी (recovery) को अलग करता है, टाइमआउट्स की लागत बताता है, और यह उम्मीद करने के बजाय कि कोई स्ट्रेस टेस्ट इसे पकड़ लेगा, इंटरलीविंग को दोबारा उत्पन्न (reproduce) करता है।

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

  • क्या सभी संसाधन सिंगल-इंस्टेंस म्यूटेक्स हैं? सिंगल-इंस्टेंस संसाधनों पर wait-for graph में एक साइकल यह साबित करता है कि वह समूह आगे नहीं बढ़ सकता। यदि किसी संसाधन प्रकार के कई इंस्टेंस हैं, तो संसाधन-आवंटन ग्राफ (resource-allocation graph) में एक साइकल केवल संभावना को इंगित करता है; उपलब्ध इंस्टेंस और शेष आवश्यकताएं अभी भी मायने रखती हैं।
  • क्या लॉक्स री-एंट्रेंट (reentrant) हैं? एक ही थ्रेड में गैर-री-एंट्रेंट लॉक को फिर से प्राप्त करने से सेल्फ-डेडलॉक हो सकता है। जब स्रोत और गंतव्य एक ही अकाउंट हों, तो यह मानने के बजाय कि सॉर्टिंग डुप्लिकेट को संभाल लेगी, लॉक करने से पहले डुप्लिकेट हटा दें (deduplicate)।
  • क्या दोनों अकाउंट परिवर्तन एक रोलबैक-सक्षम ट्रांज़ैक्शन में हैं? एक ट्रांज़ैक्शन सीमा एक विक्टिम (victim) को त्याग सकती है और पुनः प्रयास कर सकती है। एक फ़्लो जिसने पहले ही कोई बाहरी भुगतान या ईमेल भेज दिया है, उसे बिना सोचे-समझे रीप्ले करने के बजाय एक इडेम्पोटेंसी की (idempotency key) या पोस्ट-कमिट आउटबॉक्स की आवश्यकता होती है।
  • क्या प्रत्येक प्राप्ति पथ (acquisition path) एक ही ऑर्डरिंग नियम साझा कर सकता है? यदि हाँ, तो ग्लोबल ऑर्डरिंग को प्राथमिकता दें। यदि कोई थर्ड-पार्टी घटक या क्रॉस-सर्विस संसाधन उस प्रोटोकॉल में शामिल नहीं हो सकता है, तो एक साथ स्वामित्व को कम करें, स्वामित्व को नया स्वरूप दें, या एक सुरक्षित सीमा के आसपास डिटेक्शन और रोलबैक लगाएं।
  • एक अनुरोध कितनी देर तक प्रतीक्षा कर सकता है, और टाइमआउट का क्या अर्थ है? एक लॉक टाइमआउट टेल लेटेंसी को सीमित करता है लेकिन एक वैध धीमे अनुरोध को समाप्त कर सकता है। कॉलर्स को यह जानने की आवश्यकता है कि क्या ऑपरेशन पुनः प्रयास करने योग्य (retryable), अंतिम (final), या परिणाम-अज्ञात (outcome-unknown) है।
  • रनटाइम कौन सी नैदानिक सुविधाएं (diagnostic facilities) प्रदर्शित करता है? JVM थ्रेड प्रबंधन, डेटाबेस वेट व्यूज़, और कर्नेल लॉक वैलिडेटर विभिन्न लॉक वर्गों को कवर करते हैं। किसी एक टूल से कोई रिपोर्ट न आने का मतलब यह नहीं है कि एसिंक्रोनस वेट, वर्चुअल थ्रेड्स या बाहरी संसाधन भी सुरक्षित हैं।
  • क्या क्रिटिकल सेक्शन किसी नेटवर्क, डिस्क या उपयोगकर्ता-नियंत्रित ऑपरेशन को कॉल करता है? अनबाउंडेड निर्भरताएं स्वामित्व को बढ़ाती हैं और ब्लॉकिंग को बढ़ाती हैं। उन्हें बाहर ले जाएं जब तक कि कंसिस्टेंसी प्रोटोकॉल स्पष्ट रूप से प्रतीक्षा की मांग न करे और उसकी विफलता को न संभाले।

30-सेकंड उत्तर रूपरेखा

"यह डेडलॉक है: A, B द्वारा 84 को रिलीज करने का इंतज़ार करता है, जबकि B, A द्वारा 42 को रिलीज करने का इंतज़ार करता है, इसलिए wait-for graph में A → B → A शामिल है। इस मामले में पारस्परिक अपवर्जन, होल्ड एंड वेट, कोई प्रीमेप्शन नहीं, और सर्कुलर वेट मौजूद हैं। मैं अकाउंट आईडी को डिडुप्लिकेट करूंगा और सभी अकाउंट लॉक्स को एक स्थिर आरोही क्रम (stable ascending order) में प्राप्त करूंगा, और उल्टे क्रम में रिलीज करूंगा, जो प्रोटोकॉल द्वारा सर्कुलर वेट को तोड़ता है। प्रोडक्शन में, मैं थ्रेड या डेटाबेस वेट डेटा से साइकल की पुष्टि करूंगा। एक डेटाबेस विक्टिम रोल बैक होता है और एक सीमा के साथ पुनः प्रयास करता है; इन-प्रोसेस डेडलॉक के लिए मैं डायग्नोस्टिक्स को संरक्षित रखता हूं और केवल एक सुरक्षित स्थिति सीमा पर ही रिकवर करता हूं। एक बैरियर टेस्ट पुरानी इंटरलीविंग को डिटर्मिनिस्टिक बनाता है और सत्यापित करता है कि ऑर्डर्ड संस्करण बैलेंस इनवेरिएंट को बनाए रखता है।"

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

चरण-दर-चरण विस्तृत उत्तर

चरण 1: केवल लक्षणों से निदान करने के बजाय वेट साइकल को सिद्ध करें

रनटाइम स्थिति को एक wait-for graph के रूप में दर्शाएं। थ्रेड A लॉक 42 रखता है और 84 का अनुरोध करता है, जिसका स्वामी B है, इसलिए A → B जोड़ें। थ्रेड B, 84 रखता है और 42 का अनुरोध करता है, जिसका स्वामी A है, इसलिए B → A जोड़ें। प्रत्येक थ्रेड अपना पहला लॉक दूसरा प्राप्त करने के बाद ही छोड़ता है। साइकल में कोई भी नोड पहले समाप्त नहीं हो सकता है, इसलिए समूह अपने दम पर प्रगति नहीं कर सकता है।

प्रोडक्शन डायग्नोसिस के लिए लगभग एक ही क्षण के मालिकों, वेटर्स और स्टैक्स की आवश्यकता होती है। एक थ्रेड स्नैपशॉट हानिरहित कंटेंशन को पकड़ सकता है। समान स्टैक और किनारों के साथ बार-बार लिए गए स्नैपशॉट अधिक मजबूत प्रमाण प्रदान करते हैं। एक लंबे लेकिन सामान्य इंतज़ार में कोई रिटर्न एज नहीं होता है: A, B के लिए इंतज़ार कर सकता है जबकि B निष्पादित हो रहा है और अंततः अपने संसाधन को रिलीज करता है। हर धीमे लॉक को डेडलॉक कहना क्षमता या निर्भरता विलंबता को लॉक-प्रोटोकॉल बग के रूप में गलत निदान करना है।

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

चरण 2: कोड पर चार आवश्यक शर्तों को मैप करें

इस ट्रांसफर में चारों स्थितियां ठोस हैं:

  1. पारस्परिक अपवर्जन (Mutual exclusion): एक समय में एक थ्रेड के पास किसी अकाउंट का राइट लॉक होता है।
  2. होल्ड एंड वेट (Hold and wait): 84 का अनुरोध करते समय A के पास 42 है; 42 का अनुरोध करते समय B के पास 84 है।
  3. कोई प्रीमेप्शन नहीं (No preemption): रनटाइम सुरक्षित रूप से किसी अकाउंट लॉक को उसके स्वामी से नहीं छीनता है; स्वामी ही इसे रिलीज करता है।
  4. सर्कुलर वेट (Circular wait): A, B का इंतज़ार करता है और B, A का इंतज़ार करता है।

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

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

चरण 3: एक वैश्विक लॉक क्रम (global lock order) के साथ सर्कुलर वेट को समाप्त करें

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

भाषा-तटस्थ स्यूडोकॉड (pseudocode):

transfer(fromid, toid, amount): ids = unique(sortascending([fromid, to_id])) acquired = [] try: for id in ids: acquired.append(lock_account(id)) validateandapplytransfer(fromid, to_id, amount) finally: for lock in reverse(acquired): unlock(lock)

शुद्धता का तर्क संक्षिप्त है। यदि कम रैंक वाला लॉक रखने वाला थ्रेड केवल उच्च रैंक वाले लॉक की प्रतीक्षा कर सकता है, तो एक वेट साइकल के लिए रैंकों में सख्ती से वृद्धि की आवश्यकता होगी:

r1 < r2 < … < rn < r1

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

रिवर्स रिलीज नेस्टेड स्वामित्व के बारे में तर्क करना आसान बनाता है लेकिन यह साइकल को रोकने का मुख्य कारण नहीं है। अधिक महत्वपूर्ण नियम लॉक्स रखते समय रिमोट कॉल्स, उपयोगकर्ता इनपुट और अनबाउंडेड I/O से बचना है। एक लंबा क्रिटिकल सेक्शन डेडलॉक न भी करे, लेकिन यह कंटेंशन, टाइमआउट और रिकवरी लागत को बहुत बढ़ा देता है।

चरण 4: जानें कि कब कोई अन्य रणनीति उपयुक्त होती है

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

डेडलॉक अवॉइडेंस यह पूछता है कि क्या किसी अनुरोध को स्वीकार करना एक सुरक्षित स्थिति को सुरक्षित रखता है। बैंकर एल्गोरिदम (Banker's algorithm) को अग्रिम रूप से अधिकतम मांगों की आवश्यकता होती है और यह उपलब्ध, अधिकतम, आवंटित और शेष संसाधनों को ट्रैक करता है। एक डायनामिक वेब अनुरोध शायद ही कभी हर उस ऑब्जेक्ट को जानता है जिसे वह बाद में छुएगा, इसलिए एल्गोरिदम सुरक्षित स्थितियों को समझाने के लिए उपयोगी है लेकिन आमतौर पर एप्लिकेशन कोड में कॉपी नहीं किया जाता है। एक सुरक्षित स्थिति एक पूर्णता क्रम की गारंटी देती है। एक असुरक्षित स्थिति डेडलॉक की ओर ले जा सकती है लेकिन वह पहले से डेडलॉक नहीं होती है।

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

ट्राई-लॉक (Try-lock) और टाइमआउट नुकसानदेह एस्केप मैकेनिज्म हैं, न कि साइकल-मुक्त प्रोटोकॉल का प्रमाण। यदि टाइमआउट पाथ आंशिक स्थिति को रोल बैक करता है और प्रत्येक रखे गए लॉक को रिलीज करता है, तो यह थ्रेशोल्ड के बाद होल्ड एंड वेट को तोड़ता है और इस साइकल को समाप्त कर देता है। अनुरोध अभी भी थ्रेशोल्ड से पहले रुकते हैं, और एक छोटा थ्रेशोल्ड वैध कार्य को निरस्त कर देता है। दोनों पक्ष टाइम आउट हो सकते हैं और एक साथ पुनः प्रयास कर सकते हैं, जिससे लाइव-लॉक (livelock) उत्पन्न हो सकता है। अधिकतम प्रयास गणना (maximum attempt count), रैंडमाइज्ड बैकऑफ, इडेम्पोटेंट सेमेंटिक्स और एक टर्मिनल त्रुटि का उपयोग करें।

चरण 5: बताएं कि प्रत्येक डिटेक्टर वास्तव में क्या कवर करता है

JVM ThreadMXBean ऑब्जेक्ट मॉनिटर्स या ओनेबल सिंक्रोनाइज़र्स की प्रतीक्षा कर रहे प्लेटफ़ॉर्म थ्रेड्स के बीच साइकल ढूंढ सकता है और उनकी आईडी लौटा सकता है। Java SE 25 दस्तावेज़ीकरण बताता है कि वर्चुअल थ्रेड्स वाले साइकल इस विधि द्वारा नहीं पाए जाते हैं और यह ऑपरेशन समस्या निवारण के लिए है, सिंक्रोनाइज़ेशन नियंत्रण के लिए नहीं। एक शून्य परिणाम केवल डिटेक्टर के कवरेज को स्पष्ट करता है।

लिनक्स कर्नेल का lockdep लॉक वर्गों के बीच देखे गए अधिग्रहण निर्भरताओं को रिकॉर्ड करता है। यदि निष्पादन L1 → L2 और L2 → L1 को प्रदर्शित करता है, तो यह संभावित इनवर्जन की रिपोर्ट कर सकता है, भले ही यह रन फ्रीज न हुआ हो। यह दर्शाता है कि विकास और परीक्षण वातावरण कैसे एक ऑर्डरिंग प्रोटोकॉल को मान्य कर सकते हैं; एप्लिकेशन कोड यह नहीं मान सकता कि प्रत्येक रनटाइम समान वैलिडेटर प्रदान करता है।

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

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

चरण 6: संसाधन की कंसिस्टेंसी सीमा पर रिकवर करें

डेटाबेस द्वारा किसी विक्टिम को चुनने के बाद, पूरे ट्रांज़ैक्शन को रोल बैक करें, स्थिति को फिर से पढ़ें, और फिर से निष्पादित करें। "पहले लॉक के बाद" से फिर से शुरू न करें। पुनः प्रयासों को सीमित करें और यादृच्छिक विलंब (randomized delay) जोड़ें। यदि डुप्लिकेट अनुरोध आ सकते हैं, तो एक व्यावसायिक इडेम्पोटेंसी की का उपयोग करें। कमिट के बाद एक इडेम्पोटेंट आउटबॉक्स-जैसे पाथ के माध्यम से ईमेल, मैसेजिंग या बाहरी भुगतान ट्रिगर करें क्योंकि डेटाबेस रोलबैक उत्सर्जित साइड इफ़ेक्ट को पूर्ववत नहीं कर सकता है।

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

विक्टिम चयन में पहले से किए गए कार्य, रोलबैक लागत, प्राथमिकता और पुनः प्रयास इतिहास पर विचार किया जा सकता है, लेकिन शुद्धता पहले आती है। रिकवरी प्रगति को पुनर्स्थापित करती है और कारण को नहीं हटाती है। लॉक ऑर्डर को ठीक किए बिना, वही ट्रैफ़िक फिर से डेडलॉक हो सकता है।

चरण 7: डिटर्मिनिस्टिक इंटरलीविंग के साथ फिक्स को मान्य करें

भाग्य के भरोसे केवल एक उच्च-समवर्ती परीक्षण पर निर्भर न रहें। पुराने कार्यान्वयन में एक परीक्षण बाधा (test barrier) जोड़ें। A, 42 को लॉक करने के बाद बाधा तक पहुँचता है, और B, 84 को लॉक करने के बाद उस तक पहुँचता है। दोनों को उनके दूसरे लॉक का अनुरोध करने के लिए छोड़ें। एक वॉचडॉग को परीक्षण की समय सीमा के भीतर दोनों वेट किनारों को कैप्चर करना चाहिए, जो केवल एक धीमी परीक्षण मशीन का पता लगाने के बजाय A → B → A को साबित करता है।

फिक्स के विरुद्ध समान उल्टे इनपुट चलाएं। A और B दोनों पहले लोअर आईडी 42 का प्रयास करते हैं। एक 84 का स्वामी बने बिना प्रतीक्षा करता है; विजेता 84 प्राप्त करता है, पूरा करता है, और छोड़ता है, जिसके बाद दूसरा आगे बढ़ता है। सत्यापित करें कि दोनों अनुरोधों को अनुबंध-मान्य परिणाम प्राप्त होता है, कुल बैलेंस अपरिवर्तित रहता है, और कोई भी ट्रांसफर दो बार निष्पादित नहीं होता है।

यह भी कवर करें:

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

डिटर्मिनिस्टिक परीक्षण ज्ञात प्रति-उदाहरण को बंद कर देता है। सोक अज्ञात पाथ्स की खोज करता है। प्रोटोकॉल के मान्य होने का दावा करने से पहले दोनों की आवश्यकता होती है।

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

"मैं पहले यह साबित करूंगा कि यह एक धीमे इंतज़ार से कहीं अधिक है। A के पास 42 है और वह B के 84 का इंतज़ार करता है, इसलिए A → B। B के पास 84 है और वह A के 42 का इंतज़ार करता है, इसलिए B → A। प्रत्येक सिंगल-इंस्टेंस म्यूटेक्स तभी छोड़ा जाता है जब उसके मालिक को दूसरा मिल जाता है, जिससे यह साइकल एक डेडलॉक बन जाता है।

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

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

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

सत्यापन के लिए, एक बैरियर A को 42 और B को 84 लॉक करने की अनुमति देता है, इससे पहले कि दोनों दूसरे लॉक का अनुरोध करें, जो पुराने कार्यान्वयन को मज़बूती से पुन: पेश करता है। ऑर्डर्ड संस्करण को वही उल्टे इनपुट प्राप्त होते हैं और इसे पूरा होने से पहले केवल साइकल-मुक्त प्रतीक्षा दिखानी चाहिए। मैं कुल शेष राशि, डुप्लिकेट साइड इफ़ेक्ट, डेडलॉक गणना और टर्मिनल विफलताओं की जांच करते हुए समान खातों, तीन-खाता संचालन, अपवाद क्लीनअप, बाईपास जॉब्स और डेटाबेस रोलबैक का भी परीक्षण करूंगा।"

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

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

  • जब भी कोई थ्रेड ब्लॉक हो, डेडलॉक घोषित करना → एक लंबा होल्डर अभी भी आगे बढ़ रहा हो सकता है → वेटर-टू-ओनर किनारों को बनाएं और सही संसाधन-इंस्टेंस मॉडल के तहत एक साइकल की पुष्टि करें।
  • केवल चार शर्तों को रटना → उत्तर न तो कोड को मैप करता है और न ही किसी उपाय का चयन करता है → प्रत्येक शर्त को परिदृश्य पर मैप करें और बताएं कि डिज़ाइन किसको तोड़ता है।
  • प्रत्येक फ़ंक्शन के अंदर स्वतंत्र रूप से सॉर्ट करना → मॉड्यूल की या संसाधन-प्रकार रैंक पर असहमत हो सकते हैं → एक रिपॉजिटरी-व्यापी लॉक पदानुक्रम (hierarchy) को परिभाषित करें और प्रत्येक प्रवेश बिंदु का निरीक्षण करें।
  • डुप्लिकेट संसाधन आईडी को अनदेखा करना → एक थ्रेड एक ही गैर-री-एंट्रेंट लॉक को दो बार प्राप्त कर सकता है → सॉर्ट करने से पहले डिडुप्लिकेट करें और समान-खाता ट्रांसफर सेमेंटिक्स को परिभाषित करें।
  • टाइमआउट को साइकल-मुक्त डिज़ाइन के रूप में मानना → उल्टा क्रम बना रहता है, और टाइमआउट वैध प्रतीक्षाओं को निरस्त कर सकता है → प्रत्येक रखे गए लॉक को रिलीज करें और सीमित बैकऑफ़, इडेम्पोटेंसी और टर्मिनल विफलता जोड़ें।
  • साइकल डिटेक्शन के बाद बीच में से फिर से शुरू करना → आंशिक स्थिति बासी हो सकती है और साइड इफ़ेक्ट दोहराए जा सकते हैं → एक इडेम्पोटेंट पोस्ट-कमिट पाथ के साथ पूरे ट्रांज़ैक्शन को रोल बैक करें और फिर से चलाएं।
  • यह मानना कि प्रत्येक संसाधन ग्राफ साइकल डेडलॉक साबित करता है → एक बाहरी इंस्टेंस मल्टी-इंस्टेंस संसाधन को रिलीज कर सकता है → सिंगल-इंस्टेंस wait-for graphs को मल्टी-इंस्टेंस आवंटन विश्लेषण से अलग करें।
  • लॉक के मालिक को जबरन मारना → इन-मेमोरी इनवेरिएंट्स आधे अपडेट रह सकते हैं → साक्ष्य कैप्चर करें और केवल स्थिति-पुनर्निर्माण सीमा पर पुनरारंभ करें।
  • केवल यादृच्छिक स्ट्रेस टेस्ट चलाना → पुन: पेश करने में विफलता उलटे क्रम के बारे में कुछ नहीं कहती है → बाधाओं के साथ इंटरलीविंग को ठीक करें, फिर अज्ञात पाथ्स के लिए एक सोक टेस्ट जोड़ें।

अनुवर्ती प्रश्न और उत्तर

अनुवर्ती 1: क्या ऑर्डरिंग तब भी काम करती है जब कोई ट्रांसफर तीन खातों को लॉक करता है?

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

अनुवर्ती 2: आप विभिन्न संसाधन प्रकारों को कैसे ऑर्डर करते हैं?

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

अनुवर्ती 3: क्या 100-मिलीसेकंड टाइमआउट वाले tryLock ने डेडलॉक को हल कर दिया है?

यह इस प्रयास की प्रतीक्षा को कॉन्फ़िगर की गई विंडो तक सीमित करता है लेकिन यह साइकल-मुक्त प्रोटोकॉल साबित नहीं करता है। एक सौ मिलीसेकंड भी एक वैध क्रिटिकल सेक्शन के टेल से कम हो सकता है और गलत विफलता पैदा कर सकता है। प्राप्त लॉक्स की रिलीज, आंशिक स्थिति का रोलबैक, सीमित यादृच्छिक बैकऑफ़, इडेम्पोटेंसी और एक टर्मिनल त्रुटि को परिभाषित करें; अन्यथा डेडलॉक पुनः प्रयास लाइव-लॉक बन सकता है।

अनुवर्ती 4: रीड लॉक को राइट लॉक में अपग्रेड करना खतरनाक क्यों है?

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

अनुवर्ती 5: यदि PostgreSQL स्वचालित रूप से डेडलॉक्स का पता लगाता है, तो एप्लिकेशन के लिए क्या बचता है?

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

अनुवर्ती 6: डेडलॉक, लाइव-लॉक और स्टार्वेशन में क्या अंतर है?

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

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

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