Cache-aside mit PostgreSQL und Redis

Redis-Cache-aside setzt die Anwendung zwischen einen Lesevorgang und seinen maßgeblichen Speicher. Bei einem Fehltreffer liest sie PostgreSQL, gibt diesen Wert zurück und schreibt ihn nach Redis; bei einem Schreibvorgang aktualisiert sie PostgreSQL und invalidiert den zugehörigen Redis-Schlüssel. Der Redis-Pattern-Leitfaden beschreibt diesen Ablauf, macht einen Anwendungscache aber nicht transaktional konsistent mit PostgreSQL.

Für eine Zeile mit dem Schlüssel public.items.id sieht der Ablauf so aus:

GET item:42
miss -> SELECT * FROM public.items WHERE id = $1
     -> SET item:42 <serialized row> EX <ttl>
write -> UPDATE public.items ...
      -> COMMIT
      -> DEL item:42

Verwenden Sie parametrisiertes SQL und einen Schlüssel-Namensraum. Eine TTL begrenzt, wie lange ein gespeicherter Wert in Redis bleibt; sie beweist nicht seine Aktualität relativ zu einem PostgreSQL-Commit. Explizites Löschen behandelt gewöhnliche Schreibvorgänge, entfernt aber nicht jede Race Condition.

Die Invalidation-Race-Condition

Betrachten Sie zwei Anfragen. Leser R1 findet den Schlüssel nicht in Redis und liest die alte Zeile aus PostgreSQL. Schreiber W führt einen Commit der neuen Zeile aus und löscht item:42. Danach setzt R1 die alte Zeile in Redis. Der nächste Leser sieht veraltete Daten, bis der Schlüssel abläuft oder ein weiterer Schreibvorgang ihn löscht.

Mögliche Gegenmaßnahmen sind erneutes Löschen nach Abschluss eines Ladevorgangs, das Speichern einer Datenbankversion und Zurückweisen älterer Werte, das Serialisieren von Ladevorgängen pro Schlüssel oder das Veröffentlichen bestätigter Änderungen über einen Outbox- oder CDC-Consumer. Jede Maßnahme fügt Koordination und Fehlerfälle hinzu. Der Leitfaden zur Cache- Invalidation zeigt das entsprechende Problem der späten Befüllung innerhalb von PostgreSQL.

Wo pg_local_cache passt

pg_local_cache ist eine engere PostgreSQL-lokale Option für vollständige Zeilen per Primärschlüssel. local_cache.mget ist explizit; eine gewöhnliche SELECT und eine beliebige Abfrageform lesen den Cache nie. Trigger angehängter Tabellen setzen auf dem Datenbank-Schreibpfad Sperren für betroffene Schlüssel oder Relationen, und geeignete Lesevorgänge können auf PostgreSQL zurückfallen, wenn Transaktions- oder Snapshot-Regeln einen Cache-Treffer verbieten. Beginnen Sie mit dem Leitfaden zu Batch-Abfragen und dem technischen Vertrag.

Diese Erweiterung bietet keine allgemeine Redis-Kompatibilität, keine Redis- TTLs und kein verteiltes Anwendungs-Cache-Protokoll. Ihr optionaler RESP2- Endpunkt stellt einen begrenzten authentifizierten Befehlssatz über dieselben Zuordnungen bereit und hat ein eigenes Sicherheitsmodell; TLS gibt es nicht. Verwenden Sie ihn, wenn transaktionsbewusste vollständige Zeilen-Lesevorgänge innerhalb von PostgreSQL das Problem sind. Verwenden Sie Redis, wenn mehrere Anwendungsinstanzen gemeinsame Objekte, TTL-basierte Aktualität oder Redis- Datenstrukturen benötigen. Die Kombination beider Systeme erfordert getrennte Schlüssel, Invalidation und Metriken für jede Schicht.

Starten Sie den Quickstart, vergleichen Sie ihn mit der gewöhnlichen Client-Abfrage im node-postgres-Beispiel und prüfen Sie die getrennten SQL- und RESP-Zähler. Der Leitfaden zur Caching-Entscheidung listet die anderen PostgreSQL- Optionen auf.

Aktualisiert .