बड़ी परियोजनाओं के लिए, आमतौर पर क्लाउडफ़ेयर रेट लिमिटिंग या HAProxy जैसे टूल का उपयोग करना सबसे अच्छा होता है। ये शक्तिशाली, विश्वसनीय हैं और आपके लिए भारी सामान उठाने का ख्याल रखते हैं।
लेकिन छोटी परियोजनाओं के लिए - या यदि आप सीखना चाहते हैं कि चीजें कैसे काम करती हैं - तो आप सीधे अपने कोड में अपना स्वयं का रेट लिमिटर बना सकते हैं। क्यों?
इस गाइड के अंत तक, आप जानेंगे कि अपने एपीआई को अभिभूत होने से बचाने के लिए टाइपस्क्रिप्ट में एक बुनियादी थ्रॉटलर कैसे बनाया जाए। यहां हम क्या कवर करेंगे:
यह मार्गदर्शिका एक व्यावहारिक शुरुआती बिंदु के रूप में डिज़ाइन की गई है, जो उन डेवलपर्स के लिए बिल्कुल सही है जो अनावश्यक जटिलता के बिना मूल बातें सीखना चाहते हैं। लेकिन यह उत्पादन के लिए तैयार नहीं है।
शुरू करने से पहले, मैं लूसिया के दर सीमित अनुभाग को सही श्रेय देना चाहता हूं।
आइए थ्रॉटलर वर्ग को परिभाषित करें:
export class Throttler { private storage = new Map(); constructor(private timeoutSeconds: number[]) {} }
थ्रॉटलर कंस्ट्रक्टर टाइमआउट अवधि (टाइमआउटसेकंड) की एक सूची स्वीकार करता है। हर बार जब किसी उपयोगकर्ता को ब्लॉक किया जाता है, तो इस सूची के आधार पर अवधि उत्तरोत्तर बढ़ती जाती है। अंततः, जब अंतिम समय समाप्त हो जाता है, तो आप उपयोगकर्ता के आईपी पर स्थायी रूप से प्रतिबंध लगाने के लिए कॉलबैक भी ट्रिगर कर सकते हैं - हालांकि यह इस गाइड के दायरे से परे है।
यहां थ्रॉटलर इंस्टेंस बनाने का एक उदाहरण दिया गया है जो उपयोगकर्ताओं को अंतराल बढ़ाने से रोकता है:
const throttler = new Throttler([1, 2, 4, 8, 16]);
यह इंस्टेंस उपयोगकर्ताओं को पहली बार एक सेकंड के लिए ब्लॉक कर देगा। दो के लिए दूसरी बार, इत्यादि।
हम आईपी पते और उनके संबंधित डेटा को संग्रहीत करने के लिए एक मानचित्र का उपयोग करते हैं। एक मानचित्र आदर्श है क्योंकि यह बार-बार जोड़ने और हटाने को कुशलतापूर्वक संभालता है।
प्रो टिप: गतिशील डेटा के लिए मानचित्र का उपयोग करें जो बार-बार बदलता है। स्थिर, अपरिवर्तित डेटा के लिए, एक ऑब्जेक्ट बेहतर है। (खरगोश का बिल 1)
जब आपका एंडपॉइंट एक अनुरोध प्राप्त करता है, तो यह उपयोगकर्ता का आईपी पता निकालता है और यह निर्धारित करने के लिए थ्रॉटलर से परामर्श करता है कि अनुरोध की अनुमति दी जानी चाहिए या नहीं।
केस ए: नया या निष्क्रिय उपयोगकर्ता
यदि थ्रॉटलर में आईपी नहीं मिलता है, तो यह या तो उपयोगकर्ता का पहला अनुरोध है या वे काफी समय से निष्क्रिय हैं। इस मामले में:
केस बी: सक्रिय उपयोगकर्ता
यदि आईपी पाया जाता है, तो इसका मतलब है कि उपयोगकर्ता ने पिछले अनुरोध किए हैं। यहाँ:
इस बाद वाले मामले में, हमें यह जांचने की ज़रूरत है कि क्या पिछले ब्लॉक के बाद पर्याप्त समय बीत चुका है। हम जानते हैं कि हमें किस टाइमआउटसेकंड को किसी इंडेक्स के लिए धन्यवाद देना चाहिए। यदि नहीं, तो बस वापस लौटें। अन्यथा टाइमस्टैम्प अपडेट करें।
export class Throttler { // ... public consume(key: string): boolean { const counter = this.storage.get(key) ?? null; const now = Date.now(); // Case A if (counter === null) { // At next request, will be found. // The index 0 of [1, 2, 4, 8, 16] returns 1. // That's the amount of seconds it will have to wait. this.storage.set(key, { index: 0, updatedAt: now }); return true; // allowed } // Case B const timeoutMs = this.timeoutSeconds[counter.index] * 1000; const allowed = now - counter.updatedAt >= timeoutMs; if (!allowed) { return false; // denied } // Allow the call, but increment timeout for following requests. counter.updatedAt = now; counter.index = Math.min(counter.index 1, this.timeoutSeconds.length - 1); this.storage.set(key, counter); return true; // allowed } }
इंडेक्स को अपडेट करते समय, यह टाइमआउटसेकंड के अंतिम इंडेक्स तक सीमित हो जाता है। इसके बिना, काउंटर.इंडेक्स 1 इसे ओवरफ़्लो कर देगा और इसके बाद this.timeoutSeconds[counter.index] एक्सेस के परिणामस्वरूप रनटाइम त्रुटि होगी।
यह उदाहरण दिखाता है कि थ्रॉटलर का उपयोग यह सीमित करने के लिए कैसे किया जाए कि कोई उपयोगकर्ता आपके एपीआई को कितनी बार कॉल कर सकता है। यदि उपयोगकर्ता बहुत अधिक अनुरोध करता है, तो उन्हें मुख्य तर्क चलाने के बजाय एक त्रुटि मिलेगी।
const throttler = new Throttler([1, 2, 4, 8, 16, 30, 60, 300]); export async function GET({ getClientAddress }) { const IP = getClientAddress(); if (!throttler.consume(IP)) { throw error(429, { message: 'Too Many Requests' }); } // Read from DB, call OpenAI - do the thing. return new Response(null, { status: 200 }); }
लॉगिन सिस्टम के साथ दर सीमित करने का उपयोग करते समय, आपको इस समस्या का सामना करना पड़ सकता है:
इसे रोकने के लिए, दर सीमित करने के लिए उपयोगकर्ता के आईपी के बजाय उसकी विशिष्ट उपयोगकर्ता आईडी का उपयोग करें। साथ ही, आपको अनावश्यक अवरोधों से बचने के लिए सफल लॉगिन के बाद थ्रॉटलर स्थिति को रीसेट करना होगा।
थ्रॉटलर क्लास में एक रीसेट विधि जोड़ें:
export class Throttler { // ... public reset(key: string): void { this.storage.delete(key); } }
और सफल लॉगिन के बाद इसका उपयोग करें:
const user = db.get(email); if (!throttler.consume(user.ID)) { throw error(429); } const validPassword = verifyPassword(user.password, providedPassword); if (!validPassword) { throw error(401); } throttler.reset(user.id); // Clear throttling for the user
चूंकि आपका थ्रॉटलर आईपी और दर सीमा को ट्रैक करता है, इसलिए यह सोचना महत्वपूर्ण है कि आईपी रिकॉर्ड को कैसे और कब हटाया जाए जिनकी अब आवश्यकता नहीं है। सफाई तंत्र के बिना, आपका थ्रॉटलर मेमोरी में रिकॉर्ड संग्रहीत करना जारी रखेगा, जिससे समय के साथ डेटा बढ़ने पर संभावित रूप से प्रदर्शन संबंधी समस्याएं पैदा हो सकती हैं।
इसे रोकने के लिए, आप एक क्लीनअप फ़ंक्शन लागू कर सकते हैं जो निष्क्रियता की एक निश्चित अवधि के बाद समय-समय पर पुराने रिकॉर्ड हटा देता है। थ्रॉटलर से पुरानी प्रविष्टियों को हटाने के लिए एक सरल सफाई विधि जोड़ने का एक उदाहरण यहां दिया गया है।
export class Throttler { // ... public cleanup(): void { const now = Date.now() // Capture the keys first to avoid issues during iteration (we use .delete) const keys = Array.from(this.storage.keys()) for (const key of keys) { const counter = this.storage.get(key) if (!counter) { // Skip if the counter is already deleted (handles concurrency issues) return } // If the IP is at the first timeout, remove it from storage if (counter.index == 0) { this.storage.delete(key) continue } // Otherwise, reduce the timeout index and update the timestamp counter.index -= 1 counter.updatedAt = now this.storage.set(key, counter) } } }
सफाई को शेड्यूल करने का एक बहुत ही सरल तरीका (लेकिन शायद सबसे अच्छा नहीं) सेटइंटरवल के साथ है:
const throttler = new Throttler([1, 2, 4, 8, 16, 30, 60, 300]) const oneMinute = 60_000 setInterval(() => throttler.cleanup(), oneMinute)
यह सफाई तंत्र यह सुनिश्चित करने में मदद करता है कि आपका थ्रॉटलर आपके एप्लिकेशन को कुशल रखते हुए, पुराने रिकॉर्ड को अनिश्चित काल तक नहीं रखता है। हालांकि यह दृष्टिकोण सरल और कार्यान्वयन में आसान है, अधिक जटिल उपयोग के मामलों के लिए इसे और अधिक परिष्कृत करने की आवश्यकता हो सकती है (उदाहरण के लिए, अधिक उन्नत शेड्यूलिंग का उपयोग करना या उच्च संगामिति को संभालना)।
समय-समय पर सफाई के साथ, आप मेमोरी ब्लोट को रोकते हैं और सुनिश्चित करते हैं कि जिन उपयोगकर्ताओं ने कुछ समय में अनुरोध करने का प्रयास नहीं किया है, उन्हें अब ट्रैक नहीं किया जाता है - यह आपकी दर-सीमित प्रणाली को स्केलेबल और संसाधन-कुशल दोनों बनाने की दिशा में पहला कदम है।
यदि आप साहसी महसूस कर रहे हैं, तो आपको यह पढ़ने में रुचि हो सकती है कि संपत्तियों का आवंटन कैसे किया जाता है और यह कैसे बदलता है। इसके अलावा, इनलाइन कैश जैसे वीएम अनुकूलन के बारे में क्यों नहीं, जो विशेष रूप से मोनोमोर्फिज्म द्वारा पसंद किया जाता है। आनंद लेना। ↩
अस्वीकरण: उपलब्ध कराए गए सभी संसाधन आंशिक रूप से इंटरनेट से हैं। यदि आपके कॉपीराइट या अन्य अधिकारों और हितों का कोई उल्लंघन होता है, तो कृपया विस्तृत कारण बताएं और कॉपीराइट या अधिकारों और हितों का प्रमाण प्रदान करें और फिर इसे ईमेल पर भेजें: [email protected] हम इसे आपके लिए यथाशीघ्र संभालेंगे।
Copyright© 2022 湘ICP备2022001581号-3