जब आपका API चिल्लाता है "SOS": रेट लिमिटिंग और थ्रॉटलिंग से परिचय
\n\nकल्पना करें: आपने एक आदर्श Kotlin एप्लिकेशन लिखा है। यह तेज़, सुंदर है, और कोरूटीन और Flow का उपयोग करता है। आपने इसे प्रोडक्शन में डाला, और फिर — बैम! — एक "दयालु" उपयोगकर्ता (या, इससे भी बुरा, एक हमलावर) आपके एंडपॉइंट पर प्रति सेकंड हजारों अनुरोध भेजना शुरू कर देता है। सर्वर क्रैश हो जाता है, डेटाबेस रोने लगता है, और बाकी उपयोगकर्ताओं को 503 Service Unavailable मिलता है।
परिचित दर्द है? यही कारण है कि रेट लिमिटिंग (गति सीमा) और थ्रॉटलिंग (थ्रॉटलिंग) मौजूद हैं। इस लेख में, हम केवल सिद्धांत के बारे में बात नहीं करेंगे, बल्कि व्यावहारिक उदाहरणों के साथ समझेंगे कि Kotlin में इन पैटर्न को कैसे लागू किया जाए।
\n\nहम ऐसा कोड लिखेंगे जो वास्तव में आपके बैकएंड की रक्षा करेगा, चाहे वह Ktor, Spring Boot एप्लिकेशन हो या शुद्ध कोरूटीन। चलिए शुरू करते हैं!
\n\nरेट लिमिटिंग बनाम थ्रॉटलिंग: क्या अंतर है (और यह क्यों महत्वपूर्ण है)?
\n\nआइए बुनियादी बातों से शुरू करें, ताकि शब्दों में भ्रम न हो। हालांकि इन अवधारणाओं को अक्सर समानार्थक रूप में उपयोग किया जाता है, इनमें एक बारीक अंतर है।
\n\n- \n
- रेट लिमिटिंग — एक सख्त सीमा है। "आप प्रति मिनट केवल 100 अनुरोध कर सकते हैं। 101वें के बाद — आपको
429 Too Many Requestsमिलेगा और अगले मिनट तक बैन कर दिया जाएगा"। यह सीमा के बारे में है। \n - थ्रॉटलिंग — एक नरम नियमन है। "आप 200 मिलीसेकंड में एक से अधिक बार अनुरोध नहीं भेज सकते। यदि तेज़ी से भेजते हैं — हम उन्हें कतार में डाल देंगे या बस अनदेखा कर देंगे"। यह गति के बारे में है। \n
Kotlin की दुनिया में, हम अक्सर API स्तर (मिडलवेयर) पर रेट लिमिटिंग और विशिष्ट संचालन के स्तर पर थ्रॉटलिंग लागू करते हैं (उदाहरण के लिए, बाहरी सर्वर पर अनुरोधों के साथ स्पैम न करने के लिए)।
\n\nएल्गोरिदम जो प्रत्येक Kotlin डेवलपर को जानना चाहिए
\n\nकोड लिखने से पहले, आइए एक उपकरण चुनें। तीन क्लासिक एल्गोरिदम हैं जो Kotlin आर्किटेक्चर पर पूरी तरह से फिट बैठते हैं।
\n\n1. टोकन बकेट (टोकन की बाल्टी) — सबसे लोकप्रिय
\nएक बाल्टी की कल्पना करें जिसमें हर सेकंड N नए टोकन टपकते हैं। बाल्टी की अधिकतम क्षमता (burst) होती है। अनुरोध को संसाधित करने के लिए, एक टोकन लेना होता है। यदि टोकन नहीं हैं — अनुरोध अस्वीकार कर दिया जाता है।
\nलाभ: छोटे लोड स्पाइक्स (bursts) की अनुमति देता है, कार्यान्वयन में सरल है।
\n\n2. लीकी बकेट (लीकी बाल्टी) — पीक को स्मूथ करना
\nएक छेद वाली बाल्टी। अनुरोध बाल्टी में आते हैं, और "छेद" उन्हें एक स्थिर गति से बाहर निकालता है। यदि बाल्टी ओवरफ्लो हो जाती है — अनुरोध छोड़ दिए जाते हैं।
\nलाभ: लोड को पूरी तरह से संतुलित करता है, पीक नहीं होने देता।
\n\n3. स्लाइडिंग विंडो (स्लाइडिंग विंडो) — बिना झटके के सटीकता
\nकठोर सीमाओं (जैसे "1 मिनट") के बजाय, हम एक स्लाइडिंग समय खंड देखते हैं। कार्यान्वयन में अधिक जटिल, लेकिन वास्तविक लोड को अधिक सटीक रूप से दर्शाता है।
\n\nKotlin प्रोजेक्ट्स के लिए टोकन बकेट सादगी और दक्षता के बीच एक सुनहरा मध्य मार्ग है। हम इसे लागू करेंगे।
\n\nकोड लिखना: Kotlin में स्क्रैच से रेट लिमिटर (बिना लाइब्रेरी के)
\n\nआइए कोरूटीन और Mutex का उपयोग करके एक सरल लेकिन काम करने वाला रेट लिमिटर बनाएं। यह टोकन बकेट का एक थ्रेड-सेफ संस्करण होगा।
import kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport kotlin.time.Duration\nimport kotlin.time.TimeSource\n\nclass TokenBucketRateLimiter(\n private val maxTokens: Int,\n private val refillRate: Long, // प्रति सेकंड टोकन\n private val timeSource: TimeSource = TimeSource.Monotonic\n) {\n private var tokens: Long = maxTokens.toLong()\n private var lastRefillTimestamp: Long = timeSource.markNow().elapsedNow().inWholeMilliseconds\n private val mutex = Mutex()\n\n suspend fun tryAcquire(): Boolean {\n mutex.withLock {\n refillTokens()\n return if (tokens > 0) {\n tokens--\n true\n } else {\n