Redis-Caching für Next.js 15 Apps implementieren
Next.js 15 führt standardmäßig aggressive Caching-Strategien ein. Sich bei Anwendungen auf Unternehmensebene jedoch ausschließlich auf das integrierte Dateisystem-Caching oder In-Memory-Caching zu verlassen, führt unweigerlich zu veralteten Daten, unvorhersehbarer Leistung und Deployment-Problemen. Sobald Sie über mehrere serverlose Funktionen oder Container hinweg skalieren, bricht das lokale Caching zusammen. Sie benötigen einen verteilten Cache. Sie benötigen Redis.
Dieser Leitfaden beschreibt die präzise Implementierung von Redis-Caching für Next.js 15 Apps. Wir werden eine robuste, skalierbare Architektur unter Verwendung von Upstash Redis (oder einem beliebigen anderen Redis-Anbieter) und der nativen Next.js unstable_cache-API aufbauen. So umgehen wir die unzuverlässigen Voreinstellungen und übernehmen die volle Kontrolle über unsere Datenschicht.
Das Problem
Next.js 15 verlässt sich stark auf den Cache der Fetch-API und das Route-Segment-Caching. Standardmäßig speichert das Framework die gecachten Daten im Dateisystem. Das funktioniert hervorragend für eine statische Website, die auf einer einzelnen Node.js-Instanz bereitgestellt wird.
Wenn Sie jedoch auf serverlosen Plattformen wie Vercel oder AWS Lambda deployen, skaliert Ihre Anwendung, indem sie mehrere unabhängige Instanzen startet. Instanz A hat keinen Zugriff auf den Dateisystem-Cache von Instanz B. Wenn ein Benutzer Instanz A aufruft, erhält er möglicherweise aktuelle Daten. Trifft er auf Instanz B, erhält er eventuell veraltete Daten oder löst eine unnötige Datenbankabfrage aus.
Darüber hinaus ist das Dateisystem-Caching flüchtig. Das Bereitstellen einer neuen Version Ihrer App löscht oft den gesamten Cache, was unmittelbar nach einem Deployment zu massiven Traffic-Spitzen auf Ihrer Datenbank führt (ein sogenannter Cache Stampede).
Wir benötigen einen dauerhaften, verteilten Cache, der außerhalb des Anwendungscodes liegt und Deployments übersteht.
Warum es schwierig ist
Die Integration von Redis in Next.js besteht nicht nur darin, redis.get() und redis.set() aufzurufen. Next.js 15 besitzt eine sehr eigene React Server Components (RSC) Architektur. Das Framework möchte die Caching-Schicht selbst kontrollieren.
Wenn Sie Ihre Datenbankaufrufe einfach in Redis-Befehle einpacken, arbeiten Sie gegen das Framework. Sie verlieren die Vorteile der On-Demand-Revalidierung (revalidateTag, revalidatePath) und riskieren, dem Client inkonsistente Daten bereitzustellen.
Die Herausforderung besteht darin, Redis in den Caching-Lebenszyklus von Next.js zu injizieren. Wir müssen die Lese- und Schreibvorgänge des Caches abfangen, den flüchtigen Dateisystem-Cache nahtlos durch unseren verteilten Redis-Speicher ersetzen und gleichzeitig die Kompatibilität mit den Revalidierungs-Primitiven von Next.js wahren.
Dies erfordert benutzerdefinierte Cache-Handler - eine Funktion, die in Next.js in verschiedenen experimentellen Stadien vorlag. In Next.js 15 ist die Konfiguration eines benutzerdefinierten Cache-Handlers der einzig gangbare Weg für Anwendungen mit hohem Datenverkehr.
Architektur
Unsere Architektur besteht aus drei Schichten:
- Die Anwendungsschicht (Next.js 15): React Server Components, die die Geschäftslogik ausführen und die UI rendern.
- Der Cache-Interceptor: Ein benutzerdefinierter Next.js-Cache-Handler, der
unstable_cache- undfetch-Anfragen abfängt. - Die verteilte Caching-Schicht (Redis): Ein schneller In-Memory-Schlüssel-Wert-Speicher, der die serialisierten Antworten bereithält.
Wenn eine Server-Komponente Daten anfordert:
- Das Framework ruft unseren benutzerdefinierten Cache-Handler auf.
- Der Handler prüft Redis auf den entsprechenden Schlüssel.
- Bei einem Cache-Hit (Treffer) deserialisieren wir das JSON und geben es zurück. Das Framework rendert sofort die UI.
- Bei einem Cache-Miss (Fehlschlag) führt das Framework die Datenabruflogik aus (z. B. eine Abfrage an PostgreSQL) und übergibt das Ergebnis an unseren Handler, der es in Redis schreibt, bevor es an die Komponente zurückgegeben wird.
Dies stellt sicher, dass alle serverlosen Instanzen auf dieselbe Quelle der Wahrheit zugreifen.
Implementierung
Wir werden das Paket @neshca/cache-handler verwenden. Es bietet eine robuste, produktionsreife Basis für benutzerdefinierte Next.js-Cache-Handler, die speziell für die Anbindung von Redis entwickelt wurde. Als Redis-Client verwenden wir ioredis.
1. Abhängigkeiten installieren
2. Den Redis-Client konfigurieren
Erstellen Sie eine robuste Redis-Client-Instanz. Initialisieren Sie nicht mehrere Verbindungen pro serverlosem Aufruf.
3. Den Cache-Handler erstellen
Diese Datei teilt Next.js mit, wie es mit Redis kommunizieren soll. Sie ordnet Next.js-Cache-Operationen (get, set, revalidateTag) den entsprechenden Redis-Befehlen zu.
4. Integration in Next.js
Weisen Sie Next.js in der next.config.js an, Ihren benutzerdefinierten Cache-Handler zu verwenden.
5. Daten abrufen
Verwenden Sie nun unstable_cache oder das native fetch wie gewohnt. Das Framework leitet das Caching transparent über Redis.
Wenn Sie diese Daten invalidieren müssen (z. B. über einen Webhook im Administrations-Panel), rufen Sie einfach revalidateTag('products') auf. Der Cache-Handler übersetzt dies in ein Redis DEL oder eine tag-basierte Invalidierung, was sicherstellt, dass die nächste Anfrage die Datenbank trifft.
Fallstricke
Die Implementierung von Redis-Caching in Next.js 15 birgt einige architektonische Risiken. Vermeiden Sie diese typischen Fehler.
1. Redis-Latenz und Timeout-Storms
Redis ist extrem schnell, aber Netzwerklatenzen sind unberechenbar. Wenn Ihre Redis-Instanz ausfällt oder die Verbindungslatenz auf 2000 ms ansteigt, blockiert Ihre gesamte Next.js-App beim Warten auf den Cache.
Lösung: Setzen Sie in Ihrem Cache-Handler strikte Timeouts durch (z. B. timeoutMs: 500). Wenn Redis nicht innerhalb von 500 ms antwortet, muss der Cache-Handler den Fehler abfangen, dies als Cache-Miss behandeln und auf die Datenbank ausweichen. Verfügbarkeit geht vor Performance.
2. Serialisierung großer Objekte
Redis speichert Zeichenketten (Strings). Next.js serialisiert Ihre Daten in JSON, bevor sie an den Cache-Handler übergeben werden. Das Speichern riesiger 5-MB-JSON-Blobs, die eine komplette, nicht paginierte Tabelle darstellen, verstopft Ihre Redis-Netzwerk-I/O und verschlingt CPU-Zyklen für die Serialisierung und Deserialisierung.
Lösung: Cachen Sie nur das, was Sie wirklich benötigen. Schränken Sie Ihre Datenbankabfragen ein. Führen Sie kein SELECT * aus. Rufen Sie nur die Felder ab, die von der Komponente benötigt werden, um die Größe der Nutzlast zu reduzieren.
3. Cache Stampedes
Wenn ein viel genutzter Cache-Schlüssel abläuft oder invalidiert wird, können Hunderte von parallelen Anfragen den Server gleichzeitig treffen. Alle erleben einen Cache-Miss und fragen gleichzeitig die Datenbank für dieselbe Abfrage ab, was Ihre Hauptdatenbank lahmlegen kann.
Lösung: Das native unstable_cache von Next.js bietet bereits ein Request-Deduping pro Instanz. Für ein verteiltes Deduping benötigen Sie einen Redis-basierten Sperrmechanismus (Locking) oder setzen auf Stale-While-Revalidate-Muster (SWR), sodass der Benutzer veraltete Daten erhält, während die Revalidierung im Hintergrund stattfindet.
4. Verbindungslecks in Serverless-Umgebungen
Serverlose Umgebungen (wie Vercel-Funktionen) frieren Ausführungskontexte ein und tauen sie wieder auf. Wenn Sie bei jeder Anfrage eine neue Redis-Verbindung öffnen, schöpfen Sie Ihr Redis-Verbindungslimit sofort aus.
Lösung: Instanziieren Sie den Redis-Client außerhalb des Scopes des Request-Handlers. Nutzen Sie HTTP-basierte Redis-Clients (wie die REST-API von Upstash), wenn Sie keine dauerhaften TCP-Verbindungen aufrechterhalten können, obwohl @neshca/cache-handler persistente Clients bei korrekter Konfiguration gut unterstützt.
Ergebnis
Durch die Implementierung eines benutzerdefinierten Redis-Cache-Handlers ersetzen Sie den unvorhersehbaren, flüchtigen Dateisystem-Cache durch einen robusten, zentralisierten Datenspeicher.
Ihre Deployments löschen den Cache nicht mehr. Ihre serverlosen Instanzen greifen auf eine einzige Quelle der Wahrheit zu. Die Last auf Ihre Datenbank sinkt drastisch und Ihre Antwortzeiten stabilisieren sich über das gesamte Cluster hinweg.
Next.js 15 möchte das Caching selbst verwalten. Lassen Sie es die API kontrollieren. Aber Sie müssen die Infrastruktur kontrollieren. Redis gibt Ihnen die nötige Kontrolle, um Next.js im großen Maßstab zu betreiben. Geben Sie sich nicht mit den Standards zufrieden.
