Caching in JavaScript: Redis, Memcached und integrierte Lösungen: von A bis Z
In der modernen Webentwicklung mit Node.js hängt die Leistung einer Anwendung direkt von der Geschwindigkeit des Datenzugriffs ab. Jede Anfrage an die Datenbank, eine externe API oder das Dateisystem erzeugt eine Verzögerung, die bei steigender Last zunimmt. Caching ist eine Strategie zur temporären Speicherung häufig angefragter Daten in einem schnellen Speicher, die die Antwortzeit um das 10- bis 100-fache verkürzen kann. In diesem Artikel behandeln wir drei Ansätze zum Caching in JavaScript: integrierte Lösungen (Map, WeakMap, Modul node-cache), verteilte Systeme wie Redis und Memcached sowie deren Kombinationen.
Warum ist Caching in Node.js notwendig?
Das Hauptziel des Cachings ist es, die Last auf langsame Ressourcen (Datenbanken, Festplatten, externe Dienste) zu reduzieren und die Auslieferung von Daten an den Benutzer zu beschleunigen. In einer typischen Webanwendung mit Node.js kann der Cache Folgendes speichern:
- Ergebnisse komplexer Datenbankabfragen (Aggregationen, JOINs).
- Antworten von externen APIs (Wetter, Wechselkurse, Geodaten).
- Benutzersitzungen und Authentifizierungstoken.
- HTML-Fragmente oder ganze Seiten (SSR-Caching).
- Konfigurationsdateien und Vorlagen.
Ohne Caching führt jeder wiederholte Zugriff auf dieselben Daten zu doppelter Arbeit. Mit Cache werden Daten in Mikrosekunden aus dem Arbeitsspeicher abgerufen.
Integrierte Lösungen für Caching in JavaScript
Für einfache Szenarien oder Single-Thread-Anwendungen können native JavaScript-Datenstrukturen verwendet werden. Sie erfordern keine Installation externer Pakete, haben jedoch Einschränkungen hinsichtlich Größe und Lebensdauer.
1. Map und WeakMap
Das Objekt Map ist eine Schlüssel-Wert-Sammlung, die sich ideal für einen Cache innerhalb eines einzelnen Prozesses eignet. Beispiel eines einfachen Caches mit TTL (Time-to-Live):
class SimpleCache { constructor(ttl = 60000) { this.cache = new Map(); this.ttl = ttl; }
set(key, value) { this.cache.set(key, { value, expiry: Date.now() + this.ttl }); }
get(key) { const item = this.cache.get(key); if (!item) return null; if (Date.now() > item.expiry) { this.cache.delete(key); return null; } return item.value; }
has(key) { return this.get(key) !== null; }}
// Verwendungconst cache = new SimpleCache(5000); // TTL 5 Sekundencache.set('user:123', { name: 'Ivan' });console.log(cache.get('user:123')); // { name: 'Ivan' }WeakMap unterscheidet sich dadurch, dass seine Schlüssel nur Objekte sind und der Garbage Collector Einträge entfernen kann, wenn keine Referenzen mehr auf das Schlüsselobjekt vorhanden sind. Dies ist nützlich für das Caching von DOM-Elementen oder temporären Objekten.
2. Das Modul node-cache
Für die Produktionsumgebung ist es besser, die fertige Bibliothek node-cache zu verwenden. Sie unterstützt TTL, automatische Bereinigung und arbeitet schneller als eine selbstgeschriebene Lösung:
const NodeCache = require('node-cache');const myCache = new NodeCache({ stdTTL: 100, checkperiod: 120 });
// SchreibenmyCache.set('key', { data: 'value' });
// Lesenconst value = myCache.get('key');if (value === undefined) { // Cache-Fehltreffer – Daten müssen aus der DB geholt werden}
// LöschenmyCache.del('key');Integrierte Lösungen eignen sich für monolithische Anwendungen oder Microservices mit einer Instanz. Bei der Skalierung auf mehrere Prozesse oder Server werden die Daten jedoch inkonsistent – hier sind verteilte Caches erforderlich.
Redis: Leistungsstarker In-Memory-Datenspeicher
Redis ist ein Hochleistungs-In-Memory-Datenspeicher, der Strings, Hashes, Listen, Mengen und andere Datenstrukturen unterstützt. Für Node.js wird das Paket redis oder ioredis verwendet. Redis ist ideal zum Caching aufgrund von:
- Unterstützung von TTL auf Schlüsselebene (Befehl
EXPIRE). - Atomaren Operationen (INC