Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Redis

क्लाउडफ्लेयर वर्कर्स और सर्वरलेस रेडिस के साथ कस्टम वेटिंग रूम बनाएं - ट्रैफिक सर्ज को नियंत्रित करें

इस ब्लॉग पोस्ट में, हम आपकी वेबसाइट के लिए एक वेटिंग रूम पेज इम्प्लीमेंट करेंगे।

क्यों?

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

कैसे?

वेटिंग रूम को नियंत्रित करने के लिए दो पैरामीटर हैं।

  • अधिकतम सेशन अवधि: एक विज़िटर वेबसाइट पर कितनी देर तक निष्क्रिय रह सकता है?
  • अधिकतम वेबसाइट क्षमता: वेबसाइट एक साथ कितने विज़िटर की अनुमति दे सकती है?

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

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

हम इस लॉजिक को क्लाउडफ्लेयर वर्कर्स पर इम्प्लीमेंट करेंगे। हम अपस्टैश का उपयोग रेडिस स्टोर के रूप में करेंगे। अब आइए इन टेक्नोलॉजी निर्णयों की पृष्ठभूमि समझाते हैं।

क्यों क्लाउडफ्लेयर वर्कर्स?

वेटिंग रूम इम्प्लीमेंटेशन आपकी वेबसाइट के सभी रिक्वेस्ट को इंटरसेप्ट करेगा। इसलिए इसका परफॉरमेंस ओवरहेड न्यूनतम होना चाहिए। क्लाउडफ्लेयर वर्कर्स क्लाउडफ्लेयर एज इंफ्रास्ट्रक्चर का लाभ उठाता है, इसलिए यह आपको विश्व स्तर पर न्यूनतम लेटेंसी देता है। AWS लैम्ब्डा के विपरीत, इसमें कोल्ड स्टार्ट समस्या नहीं है। यह एक सर्वरलेस टेक्नोलॉजी है इसलिए स्केलेबिलिटी भी कोई समस्या नहीं है।

क्यों अपस्टैश रेडिस?

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

चरण-दर-चरण इम्प्लीमेंटेशन

हम नीचे चरण-दर-चरण प्रोजेक्ट इम्प्लीमेंट करेंगे। यदि आप प्रोजेक्ट को क्लोन करना चाहते हैं और सीधे अपनी वेबसाइट के लिए वेटिंग रूम सेटअप करना चाहते हैं, तो आप सोर्स कोड के README में चरणों का पालन कर सकते हैं।

1. प्रोजेक्ट सेटअप

वैंगलर का उपयोग करके प्रोजेक्ट बनाएं।

wrangler generate waiting-room

फिर डिपेंडेंसीज इंस्टॉल करें:

npm install cookie @upstash/redis

2. wrangler.toml अपडेट करें

टाइप अपडेट करें:

type = "webpack"

अपना क्लाउडफ्लेयर अकाउंट आईडी सेट करें। अपना अकाउंट आईडी खोजने के लिए यहां देखें।

account_id = "REPLACE_HERE"

ये वेरिएबल्स जोड़ें:

[vars]
UPSTASH_REDIS_REST_TOKEN = "REPLACE_HERE"
UPSTASH_REDIS_REST_URL = "REPLACE_HERE"
TOTAL_ACTIVE_USERS = 10
SESSION_DURATION_SECONDS = 30

आपको अपस्टैश कंसोल से एक ग्लोबल डेटाबेस बनाना होगा। आपको बस कंसोल से REST टोकन और URL कॉपी और पेस्ट करने होंगे। रेडिस डेटाबेस शुरू में खाली होना चाहिए और केवल इस एप्लिकेशन द्वारा उपयोग किया जाना चाहिए।

आपको अपनी आवश्यकताओं के आधार पर TOTAL_ACTIVE_USERS और SESSION_DURATION_SECONDS सेट करना चाहिए।

3. index.js

index.js क्लाउडफ्लेयर वर्कर्स इम्प्लीमेंटेशन फाइल है। तो हम सारा लॉजिक इसके अंदर डालेंगे। नीचे दिए गए कोड को इसमें कॉपी और पेस्ट करें:

import { parse } from "cookie";
import { Redis } from "@upstash/redis/cloudflare";

const redis = Redis.fromEnv();

addEventListener("fetch", (event) => {
  event.respondWith(
    handleRequest(event.request).catch(
      (err) => new Response(err.stack, { status: 500 })
    )
  );
});

const COOKIE_NAME_ID = "__waiting_room_id";
const COOKIE_NAME_TIME = "__waiting_room_last_update_time";

const init = {
  headers: {
    Authorization: "Bearer " + UPSTASH_REDIS_REST_TOKEN,
  },
};

async function handleRequest(request) {
  const { pathname } = new URL(request.url);
  if (!pathname.startsWith("/favicon")) {
    const cookie = parse(request.headers.get("Cookie") || "");
    let userId;
    
    if (cookie[COOKIE_NAME_ID] != null) {
      userId = cookie[COOKIE_NAME_ID];
    } else {
      userId = makeid(8);
    }
    
    const size = await redis.dbsize();
    console.log("current capacity:" + size);
    
    // पर्याप्त क्षमता है
    if (size < TOTAL_ACTIVE_USERS) {
      return getDefaultResponse(request, cookie, userId);
    } else {
      // साइट क्षमता भरी हुई है
      const user = await redis.get(userId);
      if (user === "1") {
        // यूजर का पहले से ही एक्टिव सेशन है
        return getDefaultResponse(request, cookie, userId);
      } else {
        // क्षमता भरी हुई है इसलिए यूजर को वेटिंग रूम पर फॉरवर्ड किया जाता है
        return getWaitingRoomResponse(userId);
      }
    }
  } else {
    return fetch(request);
  }
}

async function getDefaultResponse(request, cookie, userId) {
  // नीचे अनकमेंट करें ताकि स्टैटिक HTML कंटेंट के साथ फंक्शन टेस्ट कर सकें
  // const newResponse = new Response(default_html)
  // newResponse.headers.append('content-type', 'text/html;charset=UTF-8')
  
  const response = await fetch(request);
  const newResponse = new Response(response.body, response);
  
  const now = Date.now();
  let lastUpdate = cookie[COOKIE_NAME_TIME];
  if (!lastUpdate) lastUpdate = 0;
  
  const diff = now - lastUpdate;
  const updateInterval = (SESSION_DURATION_SECONDS * 1000) / 2;
  
  if (diff > updateInterval) {
    await redis.setex(userId, SESSION_DURATION_SECONDS, 1);
    newResponse.headers.append(
      "Set-Cookie",
      `${COOKIE_NAME_TIME}=${now}; path=/`
    );
  }
  
  newResponse.headers.append(
    "Set-Cookie",
    `${COOKIE_NAME_ID}=${userId}; path=/`
  );
  
  return newResponse;
}

async function getWaitingRoomResponse(userId) {
  const newResponse = new Response(waiting_room_html);
  newResponse.headers.set("content-type", "text/html;charset=UTF-8");
  return newResponse;
}

function makeid(length) {
  let result = "";
  const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  const charactersLength = characters.length;
  for (let i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength));
  }
  return result;
}

const waiting_room_html = `
  Waiting Room