Vor weniger als 24 Stunden habe ich einen Beitrag darüber geschrieben, wie Sie Ihre Website mithilfe des Cloudflare-Cache beschleunigen können. Seitdem habe ich jedoch den größten Teil der Logik mithilfe von Redis auf eine Fastify-Middleware verlagert. Hier erfahren Sie, warum und wie Sie es selbst tun können.
Ich bin auf zwei Probleme mit dem Cloudflare-Cache gestoßen:
Es gab noch ein paar andere Probleme, auf die ich gestoßen bin (z. B. dass ich den Cache nicht mithilfe des Mustervergleichs leeren konnte), aber diese waren für meinen Anwendungsfall nicht kritisch.
Daher habe ich beschlossen, die Logik mithilfe von Redis auf eine Fastify-Middleware zu verlagern.
[!NOTE]
Ich habe den Cloudflare-Cache für das Bild-Caching verlassen. In diesem Fall fungiert der Cloudflare-Cache effektiv als CDN.
Was folgt, ist eine kommentierte Version der Middleware, die ich geschrieben habe, um Antworten mit Fastify zwischenzuspeichern.
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<string, string>; 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<string> => { 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<string, string>; 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; });
Die Kommentare gehen durch den Code, aber hier sind einige wichtige Punkte:
Ich habe Latenztests von mehreren Standorten aus durchgeführt und die langsamste Antwortzeit für jede URL erfasst. Die Ergebnisse sind unten:
URL | Country | Origin Response Time | Cloudflare Cached Response Time | Fastify Cached Response Time |
---|---|---|---|---|
https://pillser.com/vitamins/vitamin-b1 | us-west1 | 240ms | 16ms | 40ms |
https://pillser.com/vitamins/vitamin-b1 | europe-west3 | 320ms | 10ms | 110ms |
https://pillser.com/vitamins/vitamin-b1 | australia-southeast1 | 362ms | 16ms | 192ms |
https://pillser.com/supplements/vitamin-b1-3254 | us-west1 | 280ms | 10ms | 38ms |
https://pillser.com/supplements/vitamin-b1-3254 | europe-west3 | 340ms | 12ms | 141ms |
https://pillser.com/supplements/vitamin-b1-3254 | australia-southeast1 | 362ms | 14ms | 183ms |
Im Vergleich zum Cloudflare-Cache ist der Fastify-Cache langsamer. Das liegt daran, dass der zwischengespeicherte Inhalt weiterhin vom Ursprung bereitgestellt wird, während der Cloudflare-Cache von regionalen Edge-Standorten bereitgestellt wird. Ich habe jedoch festgestellt, dass diese Reaktionszeiten ausreichen, um eine gute Benutzererfahrung zu erzielen.
Das obige ist der detaillierte Inhalt vonBeschleunigen Sie Ihre Website mit Fastify und Redis Cache. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!