EMZETT.
Login

Upstash Redis

Kurz: Ein “Serverless Redis”-Anbieter — eine In-Memory-Datenbank für schnelle, kurzlebige Daten (z. B. Sessions, Rate-Limiting-Zähler), über eine REST-API statt einer klassischen Redis-Verbindung ansprechbar.

Genauer: Zugriff läuft über eine REST-URL + Token (UPSTASH_REDIS_REST_URL/_TOKEN), die dauerhaft im Dashboard einsehbar sind. Fehlt die Verbindung, fallen viele Anwendungen in einen Fallback-Modus, was sich oft als plötzliche Langsamkeit bemerkbar macht.

Kontext bei uns: Wird bei Emzett u. a. fürs globale Rate-Limiting genutzt — als die Redis-Verbindung nach dem Umzug fehlte, führte das zu spürbar langsamen Seiten (jeder Request versuchte erfolglos, sich zu verbinden).

Im Detail

Klassisches Redis läuft normalerweise als dauerhaft geöffnete TCP-Verbindung, die in einem lang laufenden Server-Prozess gehalten wird. Serverless-Umgebungen (z. B. Vercel Functions) starten und beenden Funktionsinstanzen aber ständig neu — eine dauerhafte TCP-Verbindung passt nicht zu diesem Modell, jede neue Instanz müsste erst wieder eine teure Verbindung aufbauen. Upstash löst das, indem es Redis-Befehle über gewöhnliche HTTP-Requests entgegennimmt (GET/POST mit dem Befehl im Body statt einem eigenen Binärprotokoll) — dadurch passt es exakt in das “kurzlebige Funktionsaufrufe”-Modell, ohne Connection-Pooling-Probleme.

Typische Einsatzgebiete für eine In-Memory-Datenbank wie diese sind Daten, die schnell verfügbar sein müssen, aber nicht dauerhaft in der Haupt-Datenbank (PostgreSQL/Neon) landen müssen: Sitzungszustand, Zähler für Rate-Limiting, kurzlebige Caches, oder Feature-Flag-Werte (siehe Feature Flags). Ein wichtiger Unterschied zu einer normalen Datenbank: Redis-Werte lassen sich mit einer TTL (Time to Live) versehen — sie verschwinden automatisch nach Ablauf einer Frist, ganz ohne eigenen Cleanup-Job.

await redis.set(`ratelimit:${ip}`, count, { ex: 60 }) // läuft nach 60s automatisch ab

Mehr als nur Key-Value

Redis (und damit auch Upstash) bietet über einfache String-Werte hinaus spezialisierte Datenstrukturen, die für bestimmte Aufgaben deutlich effizienter sind als sie in einer klassischen relationalen Datenbank nachzubauen: Sorted Sets (ZADD/ZRANGE) eignen sich z. B. ideal für Leaderboards (Werte automatisch nach Score sortiert), Lists (LPUSH/RPOP) für einfache Warteschlangen, und Hashes für strukturierte Objekte unter einem einzigen Schlüssel, ohne für jedes Feld einen eigenen Redis-Key zu brauchen.

Sliding-Window vs. Fixed-Window Rate-Limiting

Für Rate-Limiting (wie oben im Beispiel) gibt es zwei gängige Strategien: Fixed Window zählt Anfragen innerhalb fester Zeitfenster (z. B. “0-60s”, “60-120s”) — einfach umzusetzen, hat aber eine Schwachstelle an den Fenstergrenzen (ein Nutzer könnte kurz vor UND kurz nach einer Grenze je das volle Limit ausschöpfen, doppelt so viele Anfragen in kurzer Zeit wie beabsichtigt). Sliding Window betrachtet stattdessen immer die letzten N Sekunden relativ zum aktuellen Zeitpunkt, unabhängig von festen Grenzen — genauer, aber etwas aufwendiger zu implementieren. Fertige Bibliotheken wie @upstash/ratelimit bieten beide Strategien direkt an, ohne sie selbst nachbauen zu müssen.

Siehe auch: Rate Limiting, TTL, Neon