12k
All articles

Buns eingebauten Redis-Client verwenden

Leitfaden zum integrierten Redis-Client von Bun: Verbindung, typisierte Befehle, Pub/Sub, Auto-Pipelining, Rate Limiting und ioredis-Wechsel.

OpenReplay Team
OpenReplay Team
Buns eingebauten Redis-Client verwenden

Bun wird mit einem eingebauten Redis-Client ausgeliefert, den Sie direkt importieren können — import { redis, RedisClient } from "bun" — sodass Sie für die meisten Caching-, Session-, Pub/Sub- und Rate-Limiting-Workloads kein ioredis oder node-redis mehr hinzufügen müssen. Buns nativer Redis-Client verfügt über eine Promise-basierte API mit integriertem Connection-Management, vollständig typisierten Responses und TLS-Unterstützung und unterstützt Redis-Serverversionen ab 7.2. Dieser Leitfaden behandelt ausschließlich diesen eingebauten Client — nicht ioredis, das auf Bun läuft, was die meisten „Redis mit Bun”-Tutorials stillschweigend demonstrieren.

Diese Unterscheidung ist wichtig. Ein verbreitetes Muster in bestehenden Bun-plus-Redis-Tutorials ist bun add ioredis gefolgt von new Redis() — das ist die Drittanbieter-Bibliothek, nicht die Runtime-API. Alles im Folgenden verwendet die API, die direkt in Bun enthalten ist.

Wichtigste Erkenntnisse

  • Importieren Sie den Client mit import { redis, RedisClient } from "bun"; die Standard-redis-Instanz liest REDIS_URL, dann VALKEY_URL, und fällt andernfalls auf redis://localhost:6379 zurück.
  • Der Client öffnet keine Verbindung, bis der erste Befehl ausgeführt wird, pipelinet Befehle automatisch und stellt die Verbindung mit exponentiellem Backoff wieder her — beginnend bei 50ms bis zu einem Maximum von 2000ms über standardmäßig 10 Wiederholungsversuche.
  • Ab Bun 1.3 umschließt der Client 66 Redis-Befehle als typisierte Methoden; redis.send(command, argsArray) führt jeden Befehl aus, der nicht umschlossen ist — was auch der heutige Weg ist, MULTI/EXEC auszuführen.
  • Pub/Sub übernimmt eine Verbindung, daher rufen Sie .duplicate() auf, um eine zweite Verbindung zum Publizieren oder Ausführen anderer Befehle zu erhalten.
  • Ab Bun 1.3.x unterstützt der eingebaute Client weder Redis Cluster noch Sentinel; verwenden Sie dafür node-redis oder ioredis.

Verbindung mit dem eingebauten Redis-Client herstellen

Der schnellste Weg ist der Standard-redis-Export, der sich lazy über Umgebungsvariablen verbindet. Standardmäßig liest der Client Verbindungsinformationen aus REDIS_URL, dann aus VALKEY_URL, und wenn keiner gesetzt ist, wird redis://localhost:6379 verwendet. Es wird kein Socket geöffnet, bis Sie den ersten Befehl ausführen.

import { redis, RedisClient } from "bun";

// Standard-Client — liest REDIS_URL / VALKEY_URL aus der Umgebung
await redis.set("hello", "world");
const result = await redis.get("hello");

// Benutzerdefinierter Client mit expliziter URL
const client = new RedisClient("redis://username:password@localhost:6379");
await client.set("counter", "0");
await client.incr("counter");

Verwenden Sie die Standard-redis-Instanz für den anwendungsweiten Zugriff; erstellen Sie Ihren eigenen RedisClient, wenn Sie eine separate Verbindung, eigene Optionen oder eine andere Datenbank benötigen. Die Bun-Redis-Dokumentation listet alle unterstützten URL-Schemata auf, einschließlich rediss:// und redis+tls:// für TLS sowie redis+unix:// für Unix-Sockets.

Das Connection-Management wird für Sie übernommen:

  • Es wird keine Verbindung hergestellt, bis ein Befehl ausgeführt wird; der erste Befehl initiiert die Verbindung, die für nachfolgende Befehle offen bleibt, bis Sie client.close() aufrufen.
  • Wenn eine Verbindung abbricht, erholt sich der Client selbstständig: Er beginnt mit einer Verzögerung von 50ms, verdoppelt diese bei jedem Versuch, begrenzt die Wiederverbindungsverzögerung auf 2000ms und wiederholt bis zu maxRetries-mal (Standard: 10).
  • Befehle, die während einer Verbindungsunterbrechung ausgeführt werden, werden in die Warteschlange gestellt, wenn enableOfflineQueue true ist (Standard), und sofort abgelehnt, wenn es false ist.

Dies sind dieselben Verhaltensweisen, die Sie andernfalls manuell in ioredis konfigurieren müssten.

Kernoperationen und der send()-Fallback

Der Client stellt typisierte Methoden für gängige Redis-Befehle bereit und konvertiert Antworten in native JavaScript-Werte, sodass Sie das meiste manuelle Parsen überspringen können:

  • Integer-Responses werden als JavaScript-Zahlen zurückgegeben;
  • Bulk- und einfache Strings als Strings;
  • Null-Bulk-Strings als null; und
  • Arrays als JavaScript-Arrays.

Es gibt auch befehlsspezifische Konvertierungen: EXISTS gibt einen Boolean statt einer Zahl zurück, und SISMEMBER gibt ebenfalls einen Boolean zurück.

Passen Sie diese Einstellungen über das Options-Objekt an:

const client = new RedisClient("redis://localhost:6379", {
  connectionTimeout: 5000,     // Standard: 10000 ms
  autoReconnect: true,         // Standard: true
  maxRetries: 10,              // Standard: 10
  enableOfflineQueue: true,    // Standard: true
  enableAutoPipelining: true,  // Standard: true
  tls: true,
});
// Strings und Ablaufzeit
await redis.set("session:123", "active");
await redis.expire("session:123", 3600); // Sekunden
const ttl = await redis.ttl("session:123");

// Zähler
await redis.set("counter", "0");
await redis.incr("counter");
await redis.decr("counter");

// exists() gibt einen Boolean zurück
const present = await redis.exists("session:123"); // true

// Hashes
await redis.hmset("user:123", ["name", "Alice", "email", "alice@example.com"]);
const [name, email] = await redis.hmget("user:123", ["name", "email"]);

Nicht jeder Befehl verfügt über eine dedizierte Methode. Alle Standardoperationen werden unterstützt — einschließlich Hashes, Listen und Sets — insgesamt 66 Befehle ab Bun 1.3. Für alles außerhalb dieses Umfangs verwenden Sie send(). Die send-Methode führt jeden Redis-Befehl aus, einschließlich solcher ohne dedizierte Methode; das erste Argument ist der Befehlsname und das zweite ein Array aus String-Argumenten.

// Raw-Command-Fallback — Name + Array aus String-Argumenten
await redis.send("LPUSH", ["mylist", "value1", "value2"]);
const list = await redis.send("LRANGE", ["mylist", "0", "-1"]);

send() ist auch der heutige Weg, Transaktionen auszuführen — die wichtigste API-Lücke des Clients, die später behandelt wird.

Pub/Sub mit .duplicate()

Redis Pub/Sub wird unterstützt, aber eine abonnierte Verbindung kann nichts anderes tun. Das Abonnieren übernimmt die RedisClient-Verbindung: Ein Client mit Abonnements kann nur subscribe() aufrufen. Um andere Befehle zu senden, erstellen Sie mit .duplicate() eine separate Verbindung. Der Subscribe-Callback empfängt zuerst die Nachricht und dann den Channel.

import { RedisClient } from "bun";

const redis = new RedisClient("redis://localhost:6379");
await redis.connect();

// Zweite Verbindung zum Publizieren / für andere Befehle
const subscriber = await redis.duplicate();

await subscriber.subscribe("notifications", (message, channel) => {
  console.log(`[${channel}] ${message}`);
});

await redis.publish("notifications", "Hello from Bun!");

Pub/Sub wurde in Bun 1.2.23 hinzugefügt, und die Dokumentation kennzeichnet es noch als experimentell — in der Praxis stabil, aber es lohnt sich, Ihre Bun-Version zu pinnen, wenn Sie davon abhängen. Abmelden mit .unsubscribe() (kein Argument löscht alle Channels; übergeben Sie einen Channel oder Listener, um den Scope einzuschränken).

Automatisches Pipelining

Der eingebaute Client pipelinet standardmäßig — Sie müssen sich nicht explizit dafür entscheiden. Der Client pipelinet Befehle automatisch, verbessert die Performance durch das Senden mehrerer Befehle in einem Batch und verarbeitet Responses, sobald sie eintreffen. Führen Sie mehrere awaited Befehle zusammen aus (zum Beispiel mit Promise.all), und sie werden in einem Batch statt in einzelnen Round-Trips gesendet:

const [a, b, c] = await Promise.all([
  redis.get("user:1:name"),
  redis.get("user:2:name"),
  redis.get("user:3:name"),
]);

Automatisches Pipelining ist der Punkt, an dem der Performance-Vorsprung gegenüber ioredis zunimmt. Bun beschreibt seinen Redis-Client als deutlich schneller als ioredis, wobei der Vorteil mit zunehmender Batch-Größe wächst. Buns veröffentlichte, reproduzierbare Zahlen aus den Release Notes von 1.2.9 belegen das: Im GET-Benchmark war Bun.redis bei Batches von 10 um 44,82% schneller, bei Batches von 100 um 58,29% schneller und bei Batches von 1000 um 85,39% schneller — ungefähr 1,85-fach beim größten Batch, kein fester Multiplikator. (Buns eigener 1.3-Release-Blog zeigt separat ein Benchmark-Diagramm, das den eingebauten Client bei mehr als dem 7,9-fachen Durchsatz von ioredis platziert — diese Zahl ist also Buns eigene veröffentlichte Angabe, keine sekundäre Berichterstattung.)

Eine Handvoll Befehle deaktiviert Auto-Pipelining, da sie zustandsbehaftet sind — darunter AUTH, INFO, MULTI, EXEC, WATCH, SUBSCRIBE und SELECT. Um Pipelining global zu deaktivieren, setzen Sie enableAutoPipelining: false.

Angewandte Muster: Cache, Sessions und Rate Limiting

Die folgenden Muster lassen sich von jedem Redis-Client übertragen; hier laufen sie vollständig auf der eingebauten API. Betrachten Sie dies als ein kleines Service-Modul.

Cache-Aside. Prüfen Sie zuerst Redis, greifen Sie bei einem Cache-Miss auf die Datenbank zurück und befüllen Sie dann den Cache mit einer TTL.

import { redis } from "bun";

async function getUser(userId: string) {
  const cacheKey = `user:${userId}`;
  const cached = await redis.get(cacheKey);
  if (cached) return JSON.parse(cached);

  const user = await db.getUser(userId);       // Ihre Datenquelle
  await redis.set(cacheKey, JSON.stringify(user));
  await redis.expire(cacheKey, 3600);          // 1 Stunde
  return user;
}

Beim Write-Through aktualisieren Sie den Cache in derselben Operation, die in die Datenbank schreibt. Bei Stale-While-Revalidate liefern Sie den gecachten Wert sofort aus und aktualisieren ihn im Hintergrund, sobald die TTL sich dem Ende nähert.

Session-Speicherung mit TTL. Speichern Sie Sessions als Hashes und lassen Sie Redis sie ablaufen.

async function createSession(userId: number, data: object) {
  const sessionId = crypto.randomUUID();
  const key = `session:${sessionId}`;
  await redis.hmset(key, [
    "userId", String(userId),
    "created", String(Date.now()),
    "data", JSON.stringify(data),
  ]);
  await redis.expire(key, 86400); // 24 Stunden
  return sessionId;
}

Sliding-Window-Rate-Limiting mit Sorted Sets. Sorted-Set-Befehle sind nicht als dedizierte Methoden umschlossen, daher ist dies ein natürlicher Einsatzort für send(). Entfernen Sie Einträge, die älter als das Zeitfenster sind, zählen Sie die verbleibenden und fügen Sie die aktuelle Anfrage hinzu.

async function rateLimit(id: string, limit = 100, windowMs = 60_000) {
  const key = `ratelimit:${id}`;
  const now = Date.now();

  await redis.send("ZREMRANGEBYSCORE", [key, "0", String(now - windowMs)]);
  const count = Number(await redis.send("ZCARD", [key]));

  if (count >= limit) return { allowed: false, remaining: 0 };

  await redis.send("ZADD", [key, String(now), `${now}-${crypto.randomUUID()}`]);
  await redis.expire(key, Math.ceil(windowMs / 1000));
  return { allowed: true, remaining: limit - count - 1 };
}

Da der Client automatisch pipelinet, wird die Sequenz ZREMRANGEBYSCORE/ZCARD/ZADD/EXPIRE effizient gebündelt, ohne manuelle Pipeline-Objekte.

Einschränkungen und wann Sie weiterhin ioredis oder node-redis verwenden sollten

Der eingebaute Client deckt die oben genannten gängigen Anwendungsfälle ab, weist jedoch ab Bun 1.3.x dokumentierte Lücken auf. Transaktionen (MULTI/EXEC) müssen über Raw-Befehle durchgeführt werden, und Redis Sentinel sowie Redis Cluster werden nicht unterstützt. Wenn Sie Clustering, Sentinel-basiertes Failover oder Redis-Stack-Module (Suche, JSON, Zeitreihen, probabilistische Datenstrukturen) benötigen, greifen Sie auf eine vollwertige Bibliothek zurück. Buns eigenes Issue zur Migration empfiehlt node-redis als bevorzugten Client für neue Projekte, mit ioredis als etablierter Alternative. Der 1.3-Blog vermerkt, dass Unterstützung für Cluster, Streams und Lua-Scripting in Arbeit ist — überprüfen Sie daher den Abschnitt „Limitations” in der Dokumentation, bevor Sie vom aktuellen Stand ausgehen, da sich diese Oberfläche noch weiterentwickelt.

FunktionalitätBun eingebaut redisnode-redis / ioredis
InstallationsschrittKeiner — wird mit Bun ausgeliefertbun add node-redis / ioredis
Auto-PipeliningStandardmäßig aktiviertKonfigurierbar / manuell
Pub/SubJa (experimentell, über .duplicate())Ja
Transaktionen (MULTI/EXEC)Nur über Raw-send()Native API
Redis ClusterNicht unterstütztUnterstützt
Redis SentinelNicht unterstütztUnterstützt
Redis-Stack-ModuleBibliothek verwendennode-redis unterstützt sie

Ein Implementierungsdetail, das einen Vorbehalt verdient: Die Dokumentation beschreibt den Client als nativ kompiliert (derzeit als in Rust implementiert charakterisiert, nach Buns 2026er Portierung weg von Zig). Dieses Detail ändert keine einzige Zeile Ihres Anwendungscodes — die API-Oberfläche ist unabhängig von der zugrunde liegenden Sprache identisch.

Für Caching, Sessions, Pub/Sub, Zähler und Rate Limiting ist der eingebaute Client ausreichend, und der Wegfall einer Abhängigkeit ist ein echter Gewinn. Sobald Sie Cluster, Sentinel, Redis Stack oder umfangreiche Transaktionsabläufe benötigen, installieren Sie node-redis. Beginnen Sie mit import { redis } from "bun" gegen einen lokalen Server, stellen Sie sicher, dass Ihr Befehlssatz abgedeckt ist, und pinnen Sie Ihre Bun-Version, damit eine sich weiterentwickelnde API Sie in der Produktion nicht überrascht.

FAQs

Wie führe ich eine Redis-Transaktion mit Buns eingebautem Client aus?

Buns eingebauter Client hat keine native MULTI/EXEC-API, daher führen Sie Transaktionen über die Raw-send()-Methode aus. Senden Sie redis.send('MULTI', []), dann Ihre Befehle in der Warteschlange, dann redis.send('EXEC', []). Da MULTI, EXEC und WATCH Auto-Pipelining deaktivieren, werden sie einzeln statt gebündelt gesendet. Wenn Sie eine reichhaltigere native Transaktions-API benötigen, bieten node-redis oder ioredis diese.

Funktioniert Buns eingebauter Redis-Client mit Redis Cluster oder Sentinel?

Nein. Ab Bun 1.3.x unterstützt der eingebaute Client weder Redis Cluster noch Redis Sentinel, wie im Abschnitt 'Limitations' der Dokumentation angegeben. Für Sharded Clustering, Sentinel-basiertes Failover oder Redis-Stack-Module wie Suche, JSON und Zeitreihen verwenden Sie stattdessen eine vollwertige Bibliothek. Buns eigenes Migration-Issue empfiehlt node-redis als bevorzugten Client für neue Projekte, mit ioredis als etablierter Alternative.

Was ist der Unterschied zwischen Buns eingebautem redis-Import und dem Ausführen von ioredis auf Bun?

Der eingebaute Client ist die Runtime-API, die Sie über import { redis, RedisClient } from 'bun' erreichen, ohne Installation und mit standardmäßigem Pipelining. Das Ausführen von ioredis bedeutet bun add ioredis und new Redis() — eine Drittanbieter-Bibliothek mit eigenem Connection-Handling. Die meisten 'Redis mit Bun'-Tutorials verwenden stillschweigend ioredis. Der eingebaute Client kommt ohne Abhängigkeiten aus; ioredis fügt native Cluster-, Sentinel- und Transaktions-APIs hinzu, die dem eingebauten Client fehlen.

Was passiert mit Befehlen, die gesendet werden, während Buns Redis-Client getrennt ist?

Befehle, die während einer Verbindungsunterbrechung ausgeführt werden, werden in die Warteschlange gestellt und nach Wiederherstellung der Verbindung erneut ausgeführt, da enableOfflineQueue standardmäßig true ist. Der Client verbindet sich automatisch neu mit exponentiellem Backoff, beginnend bei 50ms, mit Verdopplung bei jedem Versuch, begrenzt auf 2000ms, über standardmäßig 10 Wiederholungsversuche. Setzen Sie enableOfflineQueue auf false, um Befehle während einer Verbindungsunterbrechung sofort abzulehnen, anstatt sie zu puffern.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.