"यदि कोई कर्मचारी अपना काम अच्छी तरह से करना चाहता है, तो उसे पहले अपने औजारों को तेज करना होगा।" - कन्फ्यूशियस, "द एनालेक्ट्स ऑफ कन्फ्यूशियस। लू लिंगगोंग"
मुखपृष्ठ > प्रोग्रामिंग > फास्टिफ़ाई और रेडिस कैश का उपयोग करके अपनी वेबसाइट को तेज़ करें

फास्टिफ़ाई और रेडिस कैश का उपयोग करके अपनी वेबसाइट को तेज़ करें

2024-08-27 को प्रकाशित
ब्राउज़ करें:561

Speeding Up Your Website Using Fastify and Redis Cache

24 घंटे से भी कम समय पहले, मैंने क्लाउडफ़ेयर कैश का उपयोग करके अपनी वेबसाइट को तेज़ करने के तरीके के बारे में एक पोस्ट लिखी थी। हालाँकि, मैंने रेडिस का उपयोग करके अधिकांश तर्क को फास्टिफ़ाइ मिडलवेयर में स्थानांतरित कर दिया है। यहां बताया गया है कि आप इसे स्वयं क्यों और कैसे कर सकते हैं।

क्लाउडफ्लेयर कैश मुद्दे

क्लाउडफ़ेयर कैश के साथ मुझे दो समस्याओं का सामना करना पड़ा:

  • प्रतिक्रियाओं की कैशिंग सक्षम करने के बाद पृष्ठ नेविगेशन टूट गया। मैंने कुछ समय पहले रीमिक्स फ़ोरम में इस बारे में एक मुद्दा उठाया था, लेकिन इसे लिखने तक, यह अभी भी अनसुलझा है। यह स्पष्ट नहीं है कि प्रतिक्रिया को कैश करने से पेज नेविगेशन क्यों टूट रहा है, लेकिन ऐसा तभी होता है जब प्रतिक्रिया क्लाउडफ्लेयर द्वारा कैश की जाती है।
  • जैसा कि मूल पोस्ट में बताया गया है, मैं पुनर्वैधीकरण करते समय क्लाउडफ़ेयर को बासी सामग्री परोसने के लिए नहीं कह सका। ऐसा लगता है कि यह ऐसी सुविधा नहीं है जो उपलब्ध है।

कुछ अन्य समस्याएं थीं जिनका मुझे सामना करना पड़ा (जैसे पैटर्न मिलान का उपयोग करके कैश को शुद्ध करने में सक्षम नहीं होना), लेकिन वे मेरे उपयोग के मामले में महत्वपूर्ण नहीं थे।

इसलिए, मैंने Redis का उपयोग करके तर्क को फास्टिफ़ाइ मिडलवेयर में स्थानांतरित करने का निर्णय लिया।

[!टिप्पणी]
मैंने इमेज कैशिंग के लिए क्लाउडफ्लेयर कैश छोड़ा। इस मामले में, क्लाउडफ्लेयर कैश प्रभावी रूप से एक सीडीएन के रूप में कार्य करता है।

मिडलवेयर को तेज़ करें

इसके बाद मिडलवेयर का एक एनोटेटेड संस्करण है जिसे मैंने फास्टिफ़ाइ का उपयोग करके कैश प्रतिक्रियाओं के लिए लिखा था।

const isCacheableRequest = (request: FastifyRequest): boolean => {
  // Do not attempt to use cache for authenticated visitors.
  if (request.visitor?.userAccount) {
    return false;
  }

  if (request.method !== 'GET') {
    return false;
  }

  // We only want to cache responses under /supplements/.
  if (!request.url.includes('/supplements/')) {
    return false;
  }

  // We provide a mechanism to bypass the cache.
  // This is necessary for implementing the "Serve Stale Content While Revalidating" feature.
  if (request.headers['cache-control'] === 'no-cache') {
    return false;
  }

  return true;
};

const isCacheableResponse = (reply: FastifyReply): boolean => {
  if (reply.statusCode !== 200) {
    return false;
  }

  // We don't want to cache responses that are served from the cache.
  if (reply.getHeader('x-pillser-cache') === 'HIT') {
    return false;
  }

  // We only want to cache responses that are HTML.
  if (!reply.getHeader('content-type')?.toString().includes('text/html')) {
    return false;
  }

  return true;
};

const generateRequestCacheKey = (request: FastifyRequest): string => {
  // We need to namespace the cache key to allow an easy purging of all the cache entries.
  return 'request:'   generateHash({
    algorithm: 'sha256',
    buffer: stringifyJson({
      method: request.method,
      url: request.url,
      // This is used to cache viewport specific responses.
      viewportWidth: request.viewportWidth,
    }),
    encoding: 'hex',
  });
};

type CachedResponse = {
  body: string;
  headers: Record;
  statusCode: number;
};

const refreshRequestCache = async (request: FastifyRequest) => {
  await got({
    headers: {
      'cache-control': 'no-cache',
      'sec-ch-viewport-width': String(request.viewportWidth),
      'user-agent': request.headers['user-agent'],
    },
    method: 'GET',
    url: pathToAbsoluteUrl(request.originalUrl),
  });
};

app.addHook('onRequest', async (request, reply) => {
  if (!isCacheableRequest(request)) {
    return;
  }

  const cachedResponse = await redis.get(generateRequestCacheKey(request));

  if (!cachedResponse) {
    return;
  }

  reply.header('x-pillser-cache', 'HIT');

  const response: CachedResponse = parseJson(cachedResponse);

  reply.status(response.statusCode);
  reply.headers(response.headers);
  reply.send(response.body);
  reply.hijack();

  setImmediate(() => {
    // After the response is sent, we send a request to refresh the cache in the background.
    // This effectively serves stale content while revalidating.
    // Therefore, this cache does not reduce the number of requests to the origin;
    // The goal is to reduce the response time for the user.
    refreshRequestCache(request);
  });
});

const readableToString = (readable: Readable): Promise => {
  const chunks: Uint8Array[] = [];

  return new Promise((resolve, reject) => {
    readable.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
    readable.on('error', (err) => reject(err));
    readable.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
  });
};

app.addHook('onSend', async (request, reply, payload) => {
  if (reply.hasHeader('x-pillser-cache')) {
    return payload;
  }

  if (!isCacheableRequest(request) || !isCacheableResponse(reply) || !(payload instanceof Readable)) {
    // Indicate that the response is not cacheable.
    reply.header('x-pillser-cache', 'DYNAMIC');

    return payload;
  }

  const content = await readableToString(payload);

  const headers = omit(reply.getHeaders(), [
    'content-length',
    'set-cookie',
    'x-pillser-cache',
  ]) as Record;

  reply.header('x-pillser-cache', 'MISS');

  await redis.setex(
    generateRequestCacheKey(request),
    getDuration('1 day', 'seconds'),
    stringifyJson({
      body: content,
      headers,
      statusCode: reply.statusCode,
    } satisfies CachedResponse),
  );

  return content;
});

टिप्पणियाँ कोड के माध्यम से चलती हैं, लेकिन यहां कुछ मुख्य बिंदु हैं:

  • कैशिंग मानदंड:
    • अनुरोध:
    • प्रमाणित उपयोगकर्ताओं के लिए प्रतिक्रियाओं को कैश न करें।
    • केवल कैश अनुरोध प्राप्त करें।
    • केवल उन यूआरएल के लिए कैश प्रतिक्रियाएं जिनमें "/पूरक/" शामिल हैं।
    • यदि अनुरोध हेडर में कैश-कंट्रोल है: नो-कैश है तो कैश को बायपास करें।
    • प्रतिक्रियाएं:
    • केवल सफल प्रतिक्रियाओं को कैश करें (स्टेटसकोड 200 है)।
    • पहले से ही कैश से दी गई प्रतिक्रियाओं को कैश न करें (x-pillser-cache: HIT)।
    • केवल सामग्री-प्रकार के साथ कैश प्रतिक्रियाएं: टेक्स्ट/एचटीएमएल।
  • कैश कुंजी जनरेशन:
    • अनुरोध विधि, यूआरएल और व्यूपोर्ट चौड़ाई वाले JSON प्रतिनिधित्व के SHA-256 हैश का उपयोग करें।
    • आसान नेमस्पेसिंग और पर्जिंग के लिए कैश कुंजी के पहले 'अनुरोध:' लगाएं।
  • अनुरोध प्रबंधन:
    • किसी अनुरोध में कैश्ड प्रतिक्रिया है या नहीं यह जांचने के लिए onRequest जीवनचक्र से जुड़ें।
    • यदि उपलब्ध हो तो कैश्ड प्रतिक्रिया परोसें, इसे x-pillser-cache: HIT से चिह्नित करें।
    • कैश्ड प्रतिक्रिया भेजने के बाद कैश को रीफ्रेश करने के लिए एक पृष्ठभूमि कार्य प्रारंभ करें, "पुनर्वैधीकरण करते समय पुरानी सामग्री परोसें" को लागू करें।
  • प्रतिक्रिया प्रबंधन:
    • प्रतिक्रियाओं को संसाधित करने और कैश करने के लिए ऑनसेंड जीवनचक्र से जुड़ें।
    • सरल कैशिंग के लिए पठनीय स्ट्रीम को स्ट्रिंग में बदलें।
    • कैश से विशिष्ट हेडर (सामग्री-लंबाई, सेट-कुकी, एक्स-पिल्सर-कैश) को बाहर निकालें।
    • नॉन-कैशेबल प्रतिक्रियाओं को x-pilser-cache: डायनामिक के रूप में चिह्नित करें।
    • एक दिन के टीटीएल (टाइम टू लिव) के साथ कैश प्रतिक्रियाएं, एक्स-पिल्सर-कैश के साथ नई प्रविष्टियों को चिह्नित करना: एमआईएसएस।

परिणाम

मैंने कई स्थानों से विलंबता परीक्षण चलाया और प्रत्येक यूआरएल के लिए सबसे धीमी प्रतिक्रिया समय कैप्चर किया। परिणाम नीचे हैं:

यूआरएल देश उत्पत्ति प्रतिक्रिया समय क्लाउडफ्लेयर कैश्ड रिस्पांस टाइम कैश्ड प्रतिक्रिया समय को तेज़ करें
https://pillser.com/vitamins/vitamin-b1 हमें-पश्चिम1 240 एमएस 16 एमएस 40 एमएस
https://pillser.com/vitamins/vitamin-b1 यूरोप-पश्चिम3 320 एमएस 10 एमएस 110 एमएस
https://pillser.com/vitamins/vitamin-b1 ऑस्ट्रेलिया-दक्षिणपूर्व1 362 एमएस 16 एमएस 192 एमएस
https://pillser.com/supplements/vitamin-b1-3254 हमें-पश्चिम1 280 एमएस 10 एमएस 38 एमएस
https://pillser.com/supplements/vitamin-b1-3254 यूरोप-पश्चिम3 340 एमएस 12 एमएस 141 एमएस
https://pillser.com/supplements/vitamin-b1-3254 ऑस्ट्रेलिया-दक्षिणपूर्व1 362 एमएस 14 एमएस 183ms

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

विज्ञप्ति वक्तव्य यह लेख यहां पुन: प्रस्तुत किया गया है: https://dev.to/lilouartz/speeding-up-your-website-using-fastify-and-redis-cache-4ck6?1 यदि कोई उल्लंघन है, तो कृपया स्टडी_गोलंग@163.com पर संपर्क करें। इसे हटाने के लिए
नवीनतम ट्यूटोरियल अधिक>

चीनी भाषा का अध्ययन करें

अस्वीकरण: उपलब्ध कराए गए सभी संसाधन आंशिक रूप से इंटरनेट से हैं। यदि आपके कॉपीराइट या अन्य अधिकारों और हितों का कोई उल्लंघन होता है, तो कृपया विस्तृत कारण बताएं और कॉपीराइट या अधिकारों और हितों का प्रमाण प्रदान करें और फिर इसे ईमेल पर भेजें: [email protected] हम इसे आपके लिए यथाशीघ्र संभालेंगे।

Copyright© 2022 湘ICP备2022001581号-3