जावा में रेट लिमिटिंग और थ्रॉटलिंग: सिद्धांत से प्रैक्टिकल कोड तक
\n\nकल्पना करें: आपका नया Java माइक्रोसर्विस अभी-अभी चालू हुआ है, और अचानक उस पर अनुरोधों का हिमस्खलन हो जाता है। कोई हमलावर नहीं, बस एक लापरवाह क्लाइंट अपनी स्क्रिप्ट में देरी लगाना भूल गया। परिणाम: डेटाबेस क्रैश हो जाता है, सर्वर दम तोड़ देता है, और उपयोगकर्ता (ईमानदार लोगों सहित) 502 Bad Gateway देखते हैं। परिचित लग रहा है?
\n\nआज हम बात करेंगे कि इससे कैसे बचा जाए। हमारी चर्चा का विषय है — जावा में रेट लिमिटिंग और थ्रॉटलिंग। ये सिर्फ DevOps की दुनिया के फैशनेबल शब्द नहीं हैं, बल्कि किसी भी सार्वजनिक API के लिए आपकी पहली सुरक्षा पंक्ति हैं। हम समझेंगे कि "रेट लिमिटिंग" और "थ्रॉटलिंग" में क्या अंतर है, लोकप्रिय एल्गोरिदम देखेंगे, और सबसे महत्वपूर्ण बात, वास्तविक कोड लिखेंगे।
\n\nयदि आप Java में कोड लिखते हैं और चाहते हैं कि आपकी सेवा किसी भी लोड के तहत चालू रहे — तो आप सही जगह पर हैं। चलिए शुरू करते हैं!
\n\nरेट लिमिटिंग बनाम थ्रॉटलिंग: क्या अंतर है?
\n\nअक्सर इन अवधारणाओं को भ्रमित किया जाता है, हालांकि ये अलग-अलग, यद्यपि संबंधित, समस्याओं का समाधान करते हैं।
\n\n- \n
- रेट लिमिटिंग — यह एक सख्त बाधा है। "एक IP से प्रति सेकंड 10 से अधिक अनुरोध नहीं"। सीमा पार की? 429 Too Many Requests प्राप्त करें। यह उचित है। \n
- थ्रॉटलिंग — यह एक नरम तंत्र है। सेवा अनुरोध को ब्लॉक नहीं करती, बल्कि उसकी प्रक्रिया को धीमा कर देती है। उदाहरण के लिए, आप अनुरोध को कतार में डालते हैं और इसे एक निश्चित गति से संसाधित करते हैं। \n
वास्तविक प्रोजेक्ट्स में, जावा में थ्रॉटलिंग अक्सर सीमित थ्रूपुट वाले थ्रेड पूल (ThreadPoolExecutor) के माध्यम से कार्यान्वित किया जाता है, और रेट लिमिटिंग काउंटर, कैश और मध्यवर्ती फिल्टर के माध्यम से।
\n\nरेट लिमिटिंग एल्गोरिदम: हथियार चुनना
\n\nकोड लिखने से पहले, आइए एक रणनीति चुनें। जावा में अनुरोध सीमा के लिए ये तीन सबसे लोकप्रिय एल्गोरिदम हैं।
\n\n1. Token Bucket (टोकन बकेट)
\nक्लासिक। हमारे पास एक "बाल्टी" है जिसमें हर सेकंड N नए टोकन टपकते हैं। अनुरोध करने के लिए, एक टोकन लेना होता है। यदि बाल्टी खाली है — अनुरोध अस्वीकार कर दिया जाता है। यह एल्गोरिदम ट्रैफिक के अचानक उछाल को अच्छी तरह से संभालता है, जिससे बाल्टी के आकार तक टोकन "अग्रिम" लिए जा सकते हैं।
\n\n2. Sliding Window (स्लाइडिंग विंडो)
\nअधिक सटीक तरीका। कैलेंडर सेकंड में अनुरोध गिनने के बजाय, हम समय की एक खिड़की को स्लाइड करते हैं। उदाहरण के लिए, "पिछले 60 सेकंड में 100 से अधिक अनुरोध नहीं"। यह प्रत्येक अंतराल की शुरुआत में "बंप" को रोकता है।
\n\n3. Fixed Window (फिक्स्ड विंडो)
\nसबसे सरल, लेकिन खतरनाक। हर N सेकंड में काउंटर रीसेट करें। समस्या: विंडो के अंत में एक हजार अनुरोध किए जा सकते हैं, और अगली विंडो की शुरुआत में एक और हजार। महत्वपूर्ण सिस्टम के लिए उपयुक्त नहीं है।
\n\nहम पहले दो पर ध्यान केंद्रित करेंगे — वे प्रदर्शन और सटीकता के बीच सबसे अच्छा संतुलन प्रदान करते हैं।
\n\nकोड लिखना: अपना खुद का रेट लिमिटर
\n\nआइए Token Bucket एल्गोरिदम का उपयोग करके जावा में रेट लिमिटर लागू करें। यह समझने के लिए एक उत्कृष्ट उदाहरण है कि सीमा प्रणाली अंदर से कैसे काम करती है।
\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicLong;\n\npublic class TokenBucketRateLimiter {\n\n private final long maxTokens; // बाल्टी का अधिकतम आकार\n private final long refillRate; // प्रति सेकंड टोकन\n private final ConcurrentHashMap<String, Bucket> buckets = new ConcurrentHashMap<>();\n\n public TokenBucketRateLimiter(long maxTokens, long refillRate) {\n this.maxTokens = maxTokens;\n this.refillRate = refillRate;\n }\n\n public boolean tryAcquire(String clientId) {\n Bucket bucket = buckets.computeIfAbsent(clientId, k -> new Bucket(maxTokens));\n return bucket.tryConsume();\n }\n\n private class Bucket {\n private final AtomicLong tokens;\n private volatile long lastRefillTimestamp;\n\n Bucket(long cap