Wann sollte man Redis als Message Broker einsetzen?
Entdecken Sie die idealen Szenarien für den Einsatz von Redis als Message Broker mit seinen beiden Hauptfunktionen: Pub/Sub und Streams. Dieser umfassende Leitfaden beschreibt die Leistungsvorteile, die geringe Latenz und die Infrastrukturvorteile von Redis-Messaging. Erfahren Sie die entscheidenden Unterschiede zwischen flüchtigem Pub/Sub und dauerhaften Streams, verstehen Sie deren Einschränkungen im Vergleich zu dedizierten Brokern wie Kafka und finden Sie praktische Anwendungsfälle – von einfacher Cache-Invalidierung bis hin zu robusten, leichtgewichtigen Aufgabenwarteschlangen –, die Ihnen helfen, das richtige Werkzeug für Ihre asynchrone Kommunikation zu wählen.
Wann sollte man Redis als Message Broker einsetzen?
Redis kann ein guter Message Broker sein, wenn die Aufgabe klein, schnell und nah an den Daten ist, die Sie bereits in Redis speichern. Es kann auch das falsche Werkzeug sein, wenn Sie starke Zustellgarantien, lange Aufbewahrung, Routing-Funktionen oder einen Broker benötigen, der auch dann zuverlässig arbeitet, wenn die Nachrichtenhistorie viel größer als der Arbeitsspeicher ist.
Die Entscheidung wird einfacher, wenn Sie aufhören zu fragen: "Kann Redis Messaging?" und stattdessen fragen: "Welche Redis-Messaging-Primitive passt zu der Fehlerart, die ich tolerieren kann?"
Redis bietet Ihnen mehrere Muster, aber zwei sind für diese Frage am wichtigsten:
- Pub/Sub für Live-Übertragungen.
- Streams für dauerhafte, protokollartige Nachrichtenverarbeitung mit Verbrauchergruppen.
Aus der Ferne wirken sie ähnlich. Operativ sind sie es nicht.
Verwenden Sie Pub/Sub, wenn das Verpassen einer Nachricht akzeptabel ist
Redis Pub/Sub ist eine Live-Übertragung. Ein Herausgeber sendet an einen Kanal. Verbundene Abonnenten empfangen die Nachricht. Redis speichert diese Nachricht nicht für getrennte Abonnenten, und es gibt keine eingebaute Bestätigung.
Das ist perfekt für einige Aufgaben:
SUBSCRIBE cache:invalidations
PUBLISH cache:invalidations 'product:123'
Wenn eine Anwendungsinstanz diese Invalidierung verpasst, weil sie im falschen Moment neu gestartet wurde, sollte die Welt nicht untergehen. Der lokale Cache sollte TTLs, Versionsprüfungen oder eine andere Möglichkeit zur Wiederherstellung haben. Pub/Sub ist ein Benachrichtigungspfad, nicht die Quelle der Wahrheit.
Gute Pub/Sub-Anwendungsfälle:
- Cache-Invalidierung zwischen Anwendungsinstanzen.
- Live-UI-Updates, bei denen Clients nur den aktuellen Zustand benötigen.
- Präsenzsignale wie "Benutzer tippt" oder "Worker-Herzschlag geändert".
- Leichte Bereitstellungs- oder Konfigurationsänderungsbenachrichtigungen.
- Fan-Out-Ereignisse, bei denen verpasste Nachrichten tolerierbar sind.
Schlechte Pub/Sub-Anwendungsfälle:
- Zahlungsabwicklung.
- E-Mail-Jobs, die irgendwann gesendet werden müssen.
- Bestandsaktualisierungen, die nicht übersprungen werden dürfen.
- Prüfprotokolle.
- Alles, bei dem ein getrennter Verbraucher später aufholen muss.
Pub/Sub ist schnell, weil es weniger tut. Das ist der Kompromiss.
Verwenden Sie Streams, wenn Verbraucher aufholen müssen
Redis Streams speichern Einträge in einer Stream-Datenstruktur:
XADD orders:events * order_id 42 status paid
Verbraucher können ab einer Position lesen:
XREAD COUNT 10 STREAMS orders:events 0
Verbrauchergruppen ermöglichen es mehreren Arbeitern, sich die Arbeit zu teilen:
XGROUP CREATE orders:events order-workers 0 MKSTREAM
XREADGROUP GROUP order-workers worker-1 COUNT 10 STREAMS orders:events >
XACK orders:events order-workers 1740000000000-0
Mit Verbrauchergruppen bleibt eine an einen Arbeiter gelieferte Nachricht in der Liste der ausstehenden Einträge, bis sie mit XACK bestätigt wird. Wenn ein Arbeiter nach dem Lesen, aber vor dem Bestätigen stirbt, kann ein anderer Arbeiter die ausstehende Arbeit überprüfen und übernehmen. Das bietet Ihnen eine Mindestens-einmal-Verarbeitung, wenn Sie den Verbraucher richtig aufbauen.
Mindestens-einmal bedeutet, dass Duplikate möglich sind. Ihr Arbeiter muss idempotent sein. Ein E-Mail-Arbeiter sollte beispielsweise aufzeichnen, dass email_job_id=abc123 gesendet wurde, bevor er versucht, es erneut zu senden. Ein Bestellarbeiter sollte vermeiden, zweimal abzurechnen, wenn er denselben Stream-Eintrag zweimal sieht.
Gute Streams-Anwendungsfälle:
- Leichte Hintergrundjobs.
- Interne Service-Ereignisse, die nach kurzen Ausfällen wiederholt werden müssen.
- Kleine bis mittlere Ereignisprotokolle.
- Arbeiterpools, bei denen jeder Job von einem Arbeiter in einer Gruppe verarbeitet werden soll.
- Aktivitätsfeeds oder Zustandsänderungsprotokolle mit begrenzter Aufbewahrung.
Streams sind nicht kostenlos. Einträge leben im Redis-Arbeitsspeicher, es sei denn, sie werden durch Ihr Design gelöscht oder laufen ab. Wenn Sie einen vielbeschäftigten Stream nie kürzen, wird der Stream zu Ihrem nächsten Speichervorfall.
Verwenden Sie Kürzung:
XADD orders:events MAXLEN ~ 100000 * order_id 42 status paid
XTRIM orders:events MAXLEN ~ 100000
Die ungefähre Kürzung mit ~ ist normalerweise billiger als die genaue Kürzung. Wählen Sie die Aufbewahrung basierend auf den Wiederherstellungsanforderungen, nicht auf Hoffnung.
Redis-Listen sind immer noch nützlich für einfache Warteschlangen
Bevor es Streams gab, verwendeten viele Redis-Warteschlangen Listen:
LPUSH jobs:email '{"to":"[email protected]"}'
BRPOP jobs:email 5
Listen sind immer noch in Ordnung für sehr einfache Warteschlangen, insbesondere wenn Sie blockierendes Pop-Verhalten benötigen und keine Verbrauchergruppen oder Historie benötigen. Die Einschränkung ist die Wiederherstellung. Wenn ein Arbeiter einen Job abholt und vor dem Beenden abstürzt, ist dieser Job verloren, es sei denn, Sie fügen eine zusätzliche Buchhaltung hinzu.
Es gibt Muster, die BRPOPLPUSH oder BLMOVE verwenden, um Jobs in eine Verarbeitungsliste zu verschieben und sie nach Erfolg zu entfernen. Diese Muster können funktionieren, aber sobald Sie ausstehende Verfolgung, Wiederholungen und mehrere Verbraucher benötigen, gibt Streams Ihnen normalerweise einen klareren Ausgangspunkt.
Wählen Sie Redis, wenn Einfachheit wichtiger ist als Broker-Funktionen
Redis-Messaging ist attraktiv, wenn Redis bereits Teil Ihres Stacks ist und die Arbeitslast bescheiden ist. Sie vermeiden den Betrieb eines weiteren verteilten Systems. Entwickler verstehen bereits Redis-Clients, Überwachung, Anmeldeinformationen und Bereitstellungspfade.
Das ist ein gültiger Grund. Operative Einfachheit hat einen echten Wert.
Redis hat auch eine sehr geringe Latenz. Wenn sich Ihre Anwendung und Redis in derselben Region oder im selben privaten Netzwerk befinden, ist das Veröffentlichen einer kleinen Benachrichtigung normalerweise billig und schnell. Für Cache-Invalidierung oder Live-Status-Updates kann ein schwererer Broker unnötig sein.
Redis ermöglicht es Ihnen auch, Zustandsänderungen und Nachrichten sorgfältig zu kombinieren. Ein Lua-Skript oder eine Transaktion kann einen Schlüssel aktualisieren und in einem Redis-seitigen Vorgang an einen Stream anhängen. Das kann für kleine Systeme nützlich sein, in denen Redis der zentrale Zustandsspeicher ist.
Der Haken ist, dass Redis nicht zu Ihrem versehentlichen Alles-Broker werden sollte. Wenn jeder Dienst beginnt, hochvolumige Streams ohne Aufbewahrungsplan hinzuzufügen, wird die "einfache" Wahl zu einem überlasteten In-Memory-Protokollspeicher.
Wählen Sie einen dedizierten Broker, wenn die Fehlerbehandlung das Produkt ist
Kafka, RabbitMQ, Pulsar, NATS JetStream und Cloud-Warteschlangendienste existieren, weil Messaging schnell kompliziert wird.
Verwenden Sie einen dedizierten Broker, wenn Sie Funktionen wie diese benötigen:
- Lange Aufbewahrung, gemessen in Wochen, Monaten oder Jahren.
- Nachrichtenhistorie, die viel größer als der Arbeitsspeicher ist.
- Dead-Letter-Warteschlangen und Wiederholungsrichtlinien, die in den Broker integriert sind.
- Verzögerte Zustellung, Prioritäten, Routing-Schlüssel, Austausch- oder Themenpartitionierung.
- Für Messaging entwickelte regionsübergreifende Replikationsmuster.
- Viele unabhängige Verbrauchergruppen, die dieselbe Ereignishistorie wiedergeben.
- Stärkere Werkzeuge für Verzögerung, Offsets, Neuausgleich und Prüfungen.
Kafka ist normalerweise besser geeignet für hochvolumige Ereignispipelines und wiederholbare Protokolle. RabbitMQ ist oft besser geeignet für anspruchsvolles Routing, Bestätigungen und Arbeitswarteschlangen. Cloud-Warteschlangen sind oft besser, wenn Sie verwaltete Haltbarkeit und einfache operative Grenzen wünschen.
Redis Streams kann nützliche Produktionsarbeitslasten bewältigen, aber es ist immer noch Redis. Seine Daten sind speicherzentriert, seine Persistenzeinstellungen müssen verstanden werden, und seine Broker-Funktionen sind absichtlich kleiner als bei dedizierten Systemen.
Ein konkreter Weg zur Entscheidung
Stellen Sie diese Fragen, bevor Sie Redis wählen:
- Kann ein Verbraucher eine Nachricht ohne Datenverlust verpassen?
- Muss ein getrennter Verbraucher aufholen?
- Wie lange müssen Nachrichten aufbewahrt werden?
- Passen die aufbewahrten Nachrichtendaten bequem in den Redis-Arbeitsspeicher?
- Gehen Arbeiter sicher mit doppelten Nachrichten um?
- Benötigen Sie Dead-Letter-Warteschlangen, verzögerte Wiederholungen, Prioritäten oder Routing-Regeln?
- Wird dieser Datenverkehr das Redis-Caching oder die Sitzungen beeinträchtigen?
Wenn verpasste Nachrichten akzeptabel sind, ist Pub/Sub möglicherweise ausreichend.
Wenn Verbraucher aufholen müssen und die Aufbewahrung begrenzt ist, sind Streams möglicherweise ausreichend.
Wenn Nachrichtendaten lange Aufbewahrung, Wiedergabe durch viele Teams, komplexes Broker-Verhalten oder starke operative Trennung benötigen, verwenden Sie einen dedizierten Broker.
Beispiel: Cache-Invalidierung
Eine Anwendung speichert Produktseiten im lokalen Prozessspeicher und in Redis. Wenn sich ein Produkt ändert, veröffentlicht der Admin-Dienst:
PUBLISH cache:invalidate product:123
Jede Webinstanz, die cache:invalidate abonniert hat, löscht ihre lokale Kopie. Wenn eine Webinstanz die Nachricht verpasst, hat ihr lokaler Eintrag immer noch eine TTL von fünf Minuten und sie überprüft auch ein Produktversionsfeld bei der nächsten Anfrage. Pub/Sub ist in Ordnung, weil es einen Wiederherstellungspfad gibt.
Die Verwendung von Kafka hier würde wahrscheinlich mehr operatives Gewicht als Wert hinzufügen.
Beispiel: Hintergrund-E-Mail-Jobs
Ein Benutzer registriert sich und Sie müssen eine Willkommens-E-Mail senden. Wenn der Arbeiter für eine Minute ausfällt, muss der Job später trotzdem gesendet werden. Pub/Sub ist eine schlechte Wahl.
Ein Redis-Stream kann funktionieren:
XADD email:jobs MAXLEN ~ 100000 * job_id abc123 type welcome user_id 42
Arbeiter lesen über eine Verbrauchergruppe, senden die E-Mail, zeichnen job_id als abgeschlossen auf und rufen XACK auf. Ein Monitor überprüft ausstehende Jobs und fordert alte zurück. Das ist vernünftig für eine bescheidene interne Warteschlange.
Wenn die E-Mail-Zustellung groß wird, verzögerte Wiederholungen, Dead-Letter-Handhabung, kundenspezifische Ratenbegrenzungen und umfangreiche operative Dashboards benötigt, sieht eine dedizierte Warteschlange besser aus.
Beispiel: Prüfereignisse
Prüfereignisse benötigen normalerweise Haltbarkeit, Suche, Aufbewahrung und manchmal rechtliche oder Compliance-Handhabung. Redis Streams kann als kurzer Puffer helfen, aber Redis sollte nicht der endgültige Prüfspeicher sein. Verwenden Sie ein dauerhaftes Protokoll, eine Datenbank, eine Objektspeicher-Pipeline oder einen verwalteten Ereignisdienst, der für Aufbewahrung und Überprüfung ausgelegt ist.
Betriebshinweise, wenn Sie Redis wählen
Für Pub/Sub:
- Konfigurieren Sie
client-output-buffer-limit pubsub. - Verwenden Sie dedizierte Abonnentenverbindungen.
- Bauen Sie Wiederverbindungs- und Neuabonnementverhalten ein.
- Behandeln Sie Nachrichten als Hinweise, nicht als dauerhafte Fakten.
Für Streams:
- Legen Sie eine Aufbewahrungsrichtlinie mit
MAXLEN,MINIDoder explizitem Kürzen fest. - Überwachen Sie ausstehende Einträge.
- Machen Sie Verbraucher idempotent.
- Verwenden Sie
XACKnur, nachdem die Arbeit erfolgreich war. - Planen Sie, wie feststeckende Nachrichten übernommen und wiederholt werden.
- Überwachen Sie Speicher, Persistenz und Replikationsverzögerung.
Redis ist ein guter Message Broker, wenn Sie den Teil von Redis auswählen, der zur Aufgabe passt. Pub/Sub ist ein Live-Signal. Streams sind ein begrenztes dauerhaftes Protokoll. Keines sollte nur gewählt werden, weil Redis bereits läuft, aber beide können die einfachste richtige Antwort sein, wenn ihr Fehlermodell zu Ihrer Anwendung passt.
Die unangenehme Mitte
Viele Teams landen in der Mitte: Pub/Sub ist zu verlustbehaftet, Kafka fühlt sich zu groß an, und RabbitMQ fühlt sich wie ein weiteres zu betreibendes System an. Redis Streams kann dort eine gute Antwort sein, aber nur, wenn Sie es als echte Warteschlange und nicht als magische Liste behandeln.
Ein gesundes Streams-Design hat Eigentum an diesen Details:
- Wer erstellt den Stream und die Verbrauchergruppe?
- Wie viele Verbraucher werden erwartet?
- Was ist das maximale Alter ausstehender Nachrichten, bevor eine Nachricht zurückgefordert wird?
- Was passiert nach wiederholtem Fehlschlag?
- Wie viel Stream-Verlauf wird aufbewahrt?
- Welches Dashboard oder welcher Alarm zeigt wachsende Verzögerung?
Ohne diese Antworten können Streams leise scheitern. Ein Arbeiter kann Nachrichten lesen und vor XACK abstürzen, sodass Einträge für immer ausstehend bleiben. Ein anderer Arbeiter kann sie nie übernehmen. Die Stream-Länge kann weiter wachsen, weil niemand das Kürzen konfiguriert hat. Der Redis-Speicher steigt, aber das Anwendungsteam denkt "die Warteschlange ist dauerhaft", also bemerken sie es nicht, bis die Instanz unter Druck gerät.
Ein einfacher Arbeiter sollte normalerweise diese Schleife ausführen:
lese eine kleine Charge
verarbeite jede Nachricht idempotent
bestätige nur erfolgreiche Nachrichten
überprüfe regelmäßig ausstehende Nachrichten
übernehme feststeckende ausstehende Nachrichten
kürze gemäß Aufbewahrungsrichtlinie
Das ist mehr Arbeit als Pub/Sub, und das ist der Punkt. Haltbarkeit verschiebt Komplexität immer irgendwohin. Redis Streams hält die Broker-Seite ziemlich klein, aber die Anwendung besitzt immer noch Wiederholungen, Dead-Letter-Verhalten und Idempotenz.
Wenn niemand im Team diese Details besitzen möchte, kann eine verwaltete Warteschlange auf lange Sicht billiger sein, auch wenn sie am ersten Tag schwerer aussieht. Der beste Broker ist nicht der schnellste in einem Benchmark. Es ist derjenige, dessen Fehlerverhalten Ihr Team um 3 Uhr morgens ohne Raten betreiben kann.