Ticketing क्या है?
Ticketing एक समर्पित लॉक सर्वर है जो ठीक एक ही काम के लिए डिज़ाइन किया गया है — डिस्ट्रिब्यूटेड लॉकिंग। यह एक ही Rust सर्वर बाइनरी है, जिसके साथ आधिकारिक भाषा-वार क्लाइंट जुड़े हैं, जो सभी बाइट दर बाइट एक जैसा बाइनरी प्रोटोकॉल लागू करते हैं। केवल दो ऑपरेशन — अधिग्रहण (acquire) और रिलीज़ — प्रति-कुंजी FIFO कतार, फेंसिंग टोकन, और एक वैकल्पिक Raft क्लस्टर जिसे आप ज़रूरत पड़ने पर चालू करते हैं। एक डिस्ट्रिब्यूटेड लॉक को जो कुछ चाहिए वह सब, और उसके अलावा कुछ नहीं।
यह स्टोर पर बने लॉक से कैसे अलग है?
प्रोडक्शन में अधिकांश डिस्ट्रिब्यूटेड लॉक किसी की-वैल्यू स्टोर पर निर्भर करते हैं — Redis के ऊपर एक Lua स्क्रिप्ट या Redlock, या ZooKeeper या etcd के सेशन और लीज़ पर बना कोई लॉक। Redis एक बेहतरीन स्टोर है, लेकिन यह डिस्ट्रिब्यूटेड लॉकिंग के लिए पुनर्प्रयोजित (repurposed) एक की-वैल्यू स्टोर है, न कि उद्देश्य-निर्मित (purpose-built) लॉक सिस्टम, और यह संरचनात्मक ओवरहेड के रूप में सामने आता है: एक सामान्य-प्रयोजन प्रोटोकॉल की पार्सिंग लागत, और सामान्य-प्रयोजन डेटा संरचनाओं का ओवरहेड, दोनों साथ आते हैं।
Ticketing को पहले दिन से ही विशेष रूप से डिस्ट्रिब्यूटेड लॉकिंग के लिए डिज़ाइन किया गया है, इसलिए हर परत लॉक के इर्द-गिर्द बनाई गई है।
- प्रोटोकॉल — फ़िक्स्ड-चौड़ाई वाले बाइनरी फ़ील्ड, न कि टेक्स्ट और न ही कोई सामान्य-प्रयोजन सीरियलाइज़ेशन फ़ॉर्मैट। मान बिना किसी पार्सिंग के सीधे बाइट ऑफ़सेट से पढ़े जाते हैं, और पाइपलाइनिंग आपको पिछली प्रतिक्रिया की प्रतीक्षा किए बिना अगला अनुरोध भेजने देती है।
- सर्वर आंतरिक भाग — पूरी स्थिति (state) एक प्रति-कुंजी FIFO कतार और एक लीज़ टाइमर मात्र है। अनुरोध पथ हीप पर आवंटन (allocate) तक नहीं करता।
- संचालन — एक सर्वर बाइनरी (या कंटेनर) शुरू करें, इसे मुट्ठी भर एनवायरनमेंट वेरिएबल से कॉन्फ़िगर करें, और आपका काम पूरा हो गया। न कोई स्कीमा डिज़ाइन, न कोई अलग स्टोर, न ही लॉकिंग से असंबंधित कोई परिचालन ज्ञान आवश्यक है।
परफ़ॉर्मेंस
- 10MB से कम मेमोरी का उपयोग करते हुए प्रति सेकंड 10 लाख से अधिक ऑपरेशन संभालता है
Ticketing क्यों
🚦 क्रम अखंडता (ऑर्डरिंग इंटीग्रिटी) — प्रत्यक्ष हैंडऑफ़ के साथ FIFO कतार
पहले आओ, पहले पाओ। जब धारक (holder) रिलीज़ करता है, तो लॉक बिना किसी पुनर्स्पर्धा (re-contention) के सीधे कतार के सबसे आगे वाले को सौंप दिया जाता है। न पोलिंग-और-रिट्राई लॉक स्पर्धा से भुखमरी (starvation) होती है, न ही रिट्राई तूफ़ान।
🛟 मृत क्लाइंट लॉक को फँसाए नहीं रखता — लीज़
यदि लॉक रखने वाली प्रक्रिया (process) मर जाती है या उसका कनेक्शन टूट जाता है, तो अधिग्रहण के समय तय किया गया lease समय बीतने के बाद सर्वर स्वचालित रूप से लॉक वापस ले लेता है और उसे अगले प्रतीक्षक को सौंप देता है। रिलीज़ करना भूल जाने से पूरा सिस्टम रुक नहीं जाता।
🔑 गलत क्रम में काम होने से रोकना — फेंसिंग टोकन
एक विफलता ऐसी है जिसे अकेला लॉक नहीं रोक सकता: एक धारक जो देर से जागता है — यह जाने बिना कि उसका lease पहले ही समाप्त हो चुका है — और फिर भी अपना काम पूरा करने का अनुरोध करता है। Ticketing हर अधिग्रहण के साथ एक क्रमिक रूप से बढ़ने वाला फेंसिंग टोकन जारी करता है। जब तक संरक्षित संसाधन (protected resource) एक ही नियम लागू करता है — "अंतिम देखे गए टोकन से कम किसी भी टोकन को अस्वीकार करें" — तब तक यह आखिरी अंतर भी बंद रहता है। पूरी व्याख्या के लिए यह कैसे काम करता है देखें।
🗳️ Raft पर बना एक रुकावट-रहित क्लस्टर
एक अकेला सर्वर खुद में पर्याप्त है, लेकिन जब आपको शून्य डाउनटाइम चाहिए, तो 3 (या 5) नोड का क्लस्टर बनाएं। हर लॉक स्थिति परिवर्तन तभी अंतिम रूप से लागू होता है जब अधिकांश नोड Raft सर्वसम्मति (consensus) के ज़रिए सहमत होते हैं, इसलिए वही लॉक कभी भी एक साथ दो बार जारी नहीं होता, भले ही लीडर मर जाए या नेटवर्क विभाजित हो जाए। यदि लीडर विफल हो जाता है, तो लगभग एक सेकंड में एक नया लीडर चुना जाता है और क्लाइंट स्वचालित रूप से स्विच हो जाते हैं। जैसे-जैसे नोड एक-एक करके बंद होते हैं — जैसे क्लाउड इंस्टेंस के रीबूट या क्रमिक रखरखाव के दौरान — सेवा तब भी चलती रहती है।
🔒 अंतर्निहित (बिल्ट-इन) प्रमाणीकरण और TLS
हर कनेक्शन, कनेक्ट होने के तुरंत बाद चैलेंज-रिस्पॉन्स टोकन प्रमाणीकरण से गुज़रता है, और टोकन कभी भी वायर पर प्लेनटेक्स्ट में नहीं भेजा जाता। जब भी ज़रूरत हो, पूरे कनेक्शन को TLS से एन्क्रिप्ट करें।
🌐 हर प्रमुख भाषा में, बाइट दर बाइट, वही प्रोटोकॉल
Rust, Java/Kotlin, JavaScript/TypeScript, Python, C#, Go, Ruby, C/C++ — हर आधिकारिक क्लाइंट वही बाइनरी प्रोटोकॉल लागू करता है, एक ऐसे API के साथ जो हर भाषा के इकोसिस्टम के लिए स्वाभाविक लगे (async या ब्लॉकिंग)। किसी भी भाषा से अधिग्रहीत लॉक, किसी भी अन्य भाषा में लिखे क्लाइंट के साथ निष्पक्ष रूप से कतार में लगता है। इंस्टॉल निर्देशों और उदाहरणों के लिए लाइब्रेरी देखें।
केवल दो ऑपरेशन
एक लॉक-ओनली सर्वर के अनुरूप, इसका सतह क्षेत्र (surface area) भी न्यूनतम है।
- जिस संसाधन की आप सुरक्षा करना चाहते हैं उससे एक कुंजी जोड़ें — जैसे
order-1234,account-77,daily-batch। - काम करने से पहले उस कुंजी को अधिग्रहित (acquire) करें — यदि कोई और उसे पकड़े हुए है, तो आप FIFO कतार में अपनी बारी की प्रतीक्षा करते हैं।
- काम पूरा होने पर उसे रिलीज़ करें — अगला प्रतीक्षक बिना किसी पुनर्स्पर्धा के तुरंत काम संभाल लेता है।
इन दो ऑपरेशनों के ऊपर केवल यही विकल्प हैं lease (स्वचालित पुनर्ग्रहण) और waitTimeout (प्रतीक्षा छोड़ना) — यही पूरा API है।
आगे क्या पढ़ें
- लॉक वास्तव में कैसे सौंपे जाते हैं और क्लस्टर कैसे चालू रहता है — यह कैसे काम करता है
- वायर पर आने-जाने वाली चीज़ों का सटीक बाइट-स्तरीय विवरण — प्रोटोकॉल (API)
- सर्वर रन कमांड जनरेट करें — Ticketing सर्वर परिनियोजन