Warum Redis für die Warteschlange?
Ich habe den Eindruck, dass Redis ein guter Kandidat für die Implementierung eines Warteschlangensystems sein kann. Bis zu diesem Zeitpunkt haben wir unsere MySQL-Datenbank mit Polling oder RabbitMQ verwendet. Mit RabbitMQ hatten wir viele Probleme - die Client-Bibliotheken sind sehr arm und fehlerhaft, und wir möchten nicht zu viele Entwicklerstunden in die Behebung dieser Probleme, ein paar Probleme mit der Serververwaltungskonsole usw. investieren Zumindest haben wir keine Zeit für Millisekunden oder sind nicht sehr leistungsintensiv. Solange ein System eine Architektur hat, die eine Warteschlange intelligent unterstützt, sind wir wahrscheinlich in guter Verfassung.
Okay, das ist der Hintergrund. Im Grunde habe ich ein sehr klassisches, einfaches Warteschlangenmodell - mehrere Produzenten, die Arbeit produzieren, und mehrere Verbraucher, die Arbeit verbrauchen, und sowohl Produzenten als auch Verbraucher müssen in der Lage sein, intelligent zu skalieren. Es stellt sich heraus, dass eine Naivität PUBSUB
nicht funktioniert, da ich nicht möchte, dass alle Abonnenten Arbeit verbrauchen. Ich möchte nur, dass ein Abonnent die Arbeit erhält. Auf den ersten Blick scheint es mir BRPOPLPUSH
ein intelligentes Design zu sein.
Können wir BRPOPLPUSH verwenden?
Das grundlegende Design mit BRPOPLPUSH
ist, dass Sie eine Arbeitswarteschlange und eine Fortschrittswarteschlange haben. Wenn ein Konsument Arbeit erhält, schiebt er das Objekt atomar in die Fortschrittswarteschlange und wenn er die Arbeit beendet, ist es LREM
es. Dies verhindert ein Blackholing der Arbeit, wenn Kunden sterben, und macht die Überwachung ziemlich mühelos. Beispielsweise können wir feststellen, ob es ein Problem gibt, das dazu führt, dass die Verbraucher für die Ausführung von Aufgaben viel Zeit in Anspruch nehmen.
Es sorgt dafür
- Arbeit wird an genau einen Verbraucher geliefert
- Die Arbeit wird in einer Status-Warteschlange abgelegt, sodass sie nicht als Konsument angesehen werden kann
Die Nachteile
- Mir kommt es ziemlich seltsam vor, dass das beste Design, das ich gefunden habe, nicht wirklich verwendet wird,
PUBSUB
da sich die meisten Blog-Posts über das Anstehen über Redis auf dieses Thema zu konzentrieren scheinen. Ich habe das Gefühl, etwas Offensichtliches zu vermissen. Der einzige Weg, den ich sehe,PUBSUB
ohne zweimal Aufgaben zu verbrauchen, besteht darin, einfach eine Benachrichtigung zu senden, dass Arbeit angekommen ist, die die Verbraucher dann nicht blockieren könnenRPOPLPUSH
. - Es ist unmöglich, mehr als ein Arbeitselement gleichzeitig anzufordern, was anscheinend ein Leistungsproblem darstellt. Für unsere Situation keine große, aber es ist ziemlich offensichtlich, dass diese Operation nicht für hohen Durchsatz oder diese Situation ausgelegt war
- Kurz gesagt: Vermisse ich etwas Dummes?
Füge außerdem den node.js-Tag hinzu, da dies die Sprache ist, mit der ich mich hauptsächlich beschäftige. Node bietet möglicherweise einige Vereinfachungen bei der Implementierung, da es sich um eine Single-Thread- und eine nicht blockierende Bibliothek handelt. Darüber hinaus verwende ich die Node-Redis-Bibliothek und die Lösungen sollten oder können auch auf ihre Stärken und Schwächen eingehen.
quelle
Ich bin bisher auf einige Schwierigkeiten gestoßen, die ich hier dokumentieren möchte.
Wie gehen Sie mit der Wiederverbindungslogik um?
Dies ist ein schweres Problem und ein besonders schweres Problem beim Entwerfen und Implementieren einer Nachrichtenwarteschlange. Nachrichten müssen in der Lage sein, sich irgendwo in die Warteschlange zu stellen, wenn die Verbraucher offline sind. Ein einfaches Pub-Sub-System ist also nicht stark genug, und die Verbraucher müssen die Verbindung im Empfangszustand wiederherstellen. Pops zu blockieren ist schwierig beizubehalten, da sie nicht idempotent sind . Zuhören sollte eine idempotente Operation sein. Wenn Sie sich jedoch mit einer Unterbrechung in Bezug auf ein blockierendes Knallen befassen, können Sie sich sehr genau überlegen, ob die Unterbrechung unmittelbar nach dem Erfolg der Operation oder unmittelbar vor dem Fehlschlagen der Operation stattgefunden hat. Das ist nicht unüberwindbar, aber unerwünscht.
Darüber hinaus sollte der Hörvorgang so einfach wie möglich sein. Idealerweise sollte es diese Eigenschaften haben:
Insbesondere habe ich mich für ein schlechtes Design entschieden, bei dem die Rückkehr in einen Blocking Pop vom Erfolg früherer Operationen abhing, die spröde waren und starkes Nachdenken erforderten.
Ich bevorzuge jetzt eine Redis PUBSUB + RPOPLPUSH-Lösung. Dies entkoppelt die Benachrichtigung über Arbeit vom Arbeitsverbrauch, wodurch wir eine saubere Hörlösung herausfiltern können. Der PUBSUB ist nur für die Anzeige von Arbeiten verantwortlich. Die atomare Natur von RPOPLPUSH ist für den Verbrauch und die Delegierung von Arbeit an genau einen Verbraucher verantwortlich. Anfangs schien diese Lösung im Vergleich zu einem blockierenden Pop unnötig kompliziert, aber jetzt sehe ich, dass die Komplikation überhaupt nicht unnötig war; es löste ein schweres Problem.
Diese Lösung ist jedoch nicht ganz trivial:
Beachten Sie, dass das PUBSUB / RPOPLPUSH-Design auch Skalierungsprobleme aufweist. Jeder Verbraucher erhält eine einfache Benachrichtigung über jede Nachricht, was bedeutet, dass dies einen unnötigen Engpass darstellt. Ich vermute, es ist möglich, Kanäle zu verwenden, um die Arbeit zu zerstören, aber dies ist wahrscheinlich ein schwieriges Design, um gut zu funktionieren.
quelle
Der Hauptgrund für die Wahl von RabbitMQ anstelle von Redis sind die Fehlerszenarien und das Clustering.
Dieser Artikel erklärt es wirklich am besten, daher werde ich nur den Link bereitstellen:
https://aphyr.com/posts/283-jepsen-redis
Redis Sentinel und neuerdings Redis Clustering sind nicht in der Lage, eine Reihe grundlegender Fehlerszenarien zu handhaben, die es zu einer schlechten Wahl für eine Warteschlange gemacht haben.
RabbitMQ hat seine eigenen Probleme, obwohl es unglaublich solide in der Produktion ist und eine gute Nachrichtenwarteschlange darstellt.
Hier ist der Beitrag für Kaninchen:
https://aphyr.com/posts/315-jepsen-rabbitmq
Wenn Sie sich das CAP-Theorum (Konsistenz, Verfügbarkeit und Partitionsbehandlung) ansehen, können Sie nur 2 von 3 auswählen. Wir nutzen RMQ für den CP (Konsistenz und Partitionsbehandlung) mit unserer Nachrichtenlast. t das Ende der Welt. Um Nachrichten nicht zu verlieren, verwenden wir Ignorieren für die Partitionsbehandlung, um Nachrichten nicht zu verlieren. Duplikate können behandelt werden, da die Quelle die UUID verwaltet.
quelle