
Ausfallsicherheit und hohe Verfügbarkeit sind umfassende Themen, daher widmen wir RabbitMQ und Kafka separate Artikel. Dieser Artikel behandelt RabbitMQ, und der nächste wird Kafka im Vergleich zu RabbitMQ behandeln. Der Artikel ist lang, also machen Sie es sich bequem.
Lassen Sie uns die Strategien zur Ausfallsicherheit, Konsistenz und hohen Verfügbarkeit (HA) sowie die Kompromisse, die in jeder Strategie eingegangen werden müssen, betrachten. RabbitMQ kann in einem Cluster von Knoten arbeiten und wird dann als verteiltes System klassifiziert. Wenn es um verteilte Systeme geht, sprechen wir oft über Konsistenz und Verfügbarkeit.
Diese Konzepte beschreiben, wie das System bei Ausfällen reagiert. Ein Ausfall der Netzwerkverbindung, ein Serverausfall, ein Festplattendefekt, temporäre Serverunzugänglichkeit aufgrund von Garbage Collection, Paketverluste oder eine Verlangsamung der Netzwerkverbindung. All dies kann zu Datenverlust oder Konflikten führen. Es scheint praktisch unmöglich zu sein, ein System gleichzeitig vollständig konsistent (ohne Datenverluste, ohne Inkonsistenzen) und verfügbar (also fähig, Lese- und Schreiboperationen entgegenzunehmen) für alle Ausfallvarianten zu betreiben.
Wir werden sehen, dass Konsistenz und Verfügbarkeit an verschiedenen Enden des Spektrums stehen und dass Sie wählen müssen, in welche Richtung Sie optimieren möchten. Die gute Nachricht ist, dass dies mit RabbitMQ möglich ist. Sie haben sozusagen „Nerd-Hebel“, um das Gleichgewicht zugunsten größerer Konsistenz oder größerer Verfügbarkeit zu verschieben.
Besonderes Augenmerk legen wir darauf, welche Konfigurationen zu Datenverlust aufgrund bestätigter Nachrichten führen. Es gibt eine Verantwortlichkeitskette zwischen Publishern, Brokern und Verbrauchern. Sobald die Nachricht an den Broker übermittelt wird, liegt es in seiner Verantwortung, die Nachricht nicht zu verlieren. Wenn der Broker dem Publisher den Erhalt der Nachricht bestätigt, erwarten wir nicht, dass sie verloren geht. Doch wir werden sehen, dass dies tatsächlich abhängig von der Konfiguration Ihres Brokers und Publishers passieren kann.
Primitives zur Stabilität eines Knotens
Stabile Warteschlangen/Routing
In RabbitMQ gibt es zwei Arten von Warteschlangen: dauerhaft (durable) und nicht dauerhaft (non-durable). Alle Warteschlangen werden in der Mnesia-Datenbank gespeichert. Dauerhafte Warteschlangen werden beim Start des Knotens erneut deklariert und überstehen somit einen Neustart, einen Systemausfall oder einen Serverfehler (solange die Daten gespeichert bleiben). Das bedeutet, solange Sie Routing (exchange) und Warteschlange als dauerhaft deklarieren, wird die Infrastruktur der Warteschlangen/Routing in den Betriebsmodus zurückkehren.
Nicht dauerhafte Warteschlangen und Routing werden beim Neustart des Knotens gelöscht.
Dauerhafte Nachrichten
Nur weil die Warteschlange langlebig ist, bedeutet das nicht, dass alle ihre Nachrichten einen Neustart des Knotens überstehen. Es werden nur die Nachrichten wiederhergestellt, die vom Publisher als beständig (persistent) markiert sind. Beständige Nachrichten belasten tatsächlich den Broker, aber wenn der Verlust einer Nachricht inakzeptabel ist, bleibt uns keine andere Wahl.

Abb. 1. Matrix der Beständigkeit
Clusterbildung mit Warteschlangen-Spiegelung
Um den Verlust des Brokers zu überstehen, benötigen wir Redundanz. Wir können mehrere RabbitMQ-Knoten in einem Cluster zusammenfassen und dann durch die Replikation von Warteschlangen zwischen mehreren Knoten zusätzliche Redundanz hinzufügen. Somit verlieren wir keine Daten und bleiben verfügbar, selbst wenn ein Knoten ausfällt.
Warteschlangen-Spiegelung:
- eine Hauptwarteschlange (Master), die alle Lese- und Schreibbefehle empfängt
- ein oder mehrere Spiegel, die alle Nachrichten und Metadaten aus der Hauptwarteschlange erhalten. Diese Spiegel dienen nicht der Skalierung, sondern ausschließlich der Redundanz.

Abb. 2. Warteschlangen-Spiegelung
Die Spiegelung wird durch die entsprechende Richtlinie festgelegt. In dieser können Sie den Replikationsfaktor und sogar die Knoten auswählen, auf denen die Warteschlange platziert werden soll. Beispiele:
ha-mode: allha-mode: exactly, ha-params: 2(ein Master und ein Spiegel)ha-mode: nodes, ha-params: rabbit@node1, rabbit@node2
Bestätigung an den Publisher
Für eine konsistente Aufzeichnung sind Bestätigungen an den Publisher (Publisher Confirms) erforderlich. Ohne diese besteht das Risiko, dass Nachrichten verloren gehen. Die Bestätigung wird an den Publisher gesendet, nachdem die Nachricht auf die Festplatte geschrieben wurde. RabbitMQ schreibt Nachrichten nicht beim Empfang, sondern in regelmäßigen Abständen, im Bereich von mehreren Hundert Millisekunden. Wenn die Warteschlange gespiegelt wird, erfolgt die Bestätigung erst, nachdem alle Spiegel ebenfalls ihre Kopie der Nachricht auf die Festplatte geschrieben haben. Das bedeutet, dass die Verwendung von Bestätigungen eine Verzögerung hinzufügt, aber wenn Datensicherheit wichtig ist, sind sie notwendig.
Ausfallsichere Warteschlange
Wenn ein Broker ausfällt oder den Dienst einstellt, fallen alle Hauptwarteschlangen (Master) auf diesem Knoten zusammen mit ihm aus. Der Cluster wählt dann das älteste Spiegelbild jedes Masters und hebt es zum neuen Master hervor.

Abb. 3. Mehrere gespiegelt Warteschlangen und deren Richtlinien.
Broker 3 fällt aus. Beachten Sie, dass das Spiegelbild der Warteschlange C auf Broker 2 zum Master erhoben wird. Zudem wird ein neues Spiegelbild für Warteschlange C auf Broker 1 erstellt. RabbitMQ versucht stets, das in Ihren Richtlinien angegebene Replikationsverhältnis aufrechtzuerhalten.

Abb. 4. Broker 3 fällt aus, was zu einem Ausfall der Warteschlange C führt.
Jetzt fällt auch Broker 1 aus! Nur noch ein Broker bleibt übrig. Das Spiegelbild der Warteschlange B wird zum Master erhoben.

Abb. 5
Broker 1 wurde wiederhergestellt. Unabhängig davon, wie erfolgreich die Daten den Verlust und die Wiederherstellung des Brokers überstanden haben, werden alle gespiegelt Nachrichten der Warteschlange beim Neustart verworfen. Dies ist wichtig zu beachten, da es Konsequenzen haben wird. Diese Konsequenzen werden wir bald näher betrachten. Somit ist Broker 1 jetzt wieder Mitglied des Clusters und das Cluster versucht, die Richtlinien einzuhalten, wodurch Spiegelungen auf Broker 1 erstellt werden.
In diesem Fall war der Verlust von Broker 1 vollständig, ebenso wie die Daten, sodass die nicht gespiegelte Warteschlange B vollständig verloren ist.

Abbildung 6. Broker 1 wird wieder in Betrieb genommen.
Broker 3 wurde wieder in Betrieb genommen, sodass die Warteschlangen A und B die auf ihm erstellten Spiegel zurückerhalten, um ihren HA-Richtlinien gerecht zu werden. Aber jetzt sind alle Hauptwarteschlangen auf einem Knoten! Das ist nicht ideal, eine gleichmäßige Verteilung zwischen den Knoten wäre besser. Leider gibt es hier keine besonderen Optionen zum Neuausbalancieren der Master. Wir werden dieses Problem später noch einmal aufgreifen, da wir zuerst die Synchronisation der Warteschlange betrachten müssen.

Abbildung 7. Broker 3 wird wieder in Betrieb genommen. Alle Hauptwarteschlangen auf einem Knoten!
So haben Sie jetzt eine Vorstellung davon, wie Spiegelungen Redundanz und Ausfallsicherheit gewährleisten. Dies sichert die Verfügbarkeit im Falle eines Ausfalls eines Knotens und schützt vor Datenverlust. Aber wir sind noch nicht fertig, denn in Wirklichkeit ist alles viel komplexer.
Synchronisierung
Wenn Sie ein neues Spiegelbild erstellen, werden alle neuen Nachrichten immer auf dieses Spiegelbild und alle anderen repliziert. Was die bestehenden Daten in der Hauptwarteschlange betrifft, können wir sie in das neue Spiegelbild replizieren, das eine vollständige Kopie des Masters wird. Wir können auch die bestehenden Nachrichten nicht replizieren und es der Hauptwarteschlange und dem neuen Spiegelbild erlauben, sich im Laufe der Zeit zu treffen, wenn neue Nachrichten ans Ende eingehen und bestehende Nachrichten aus dem Kopf der Hauptwarteschlange entfernt werden.
Eine solche Synchronisierung erfolgt automatisch oder manuell und wird durch Richtlinien für Warteschlangen gesteuert. Lassen Sie uns ein Beispiel betrachten.
Wir haben zwei gespiegelte Warteschlangen. Warteschlange A wird automatisch synchronisiert, während Warteschlange B manuell synchronisiert wird. Beide Warteschlangen haben zehn Nachrichten.

Abb. 8. Zwei Warteschlangen mit unterschiedlichen Synchronisierungsmodi
Jetzt verlieren wir Broker 3.

Abb. 9. Broker 3 ist ausgefallen
Broker 3 wird wieder in Betrieb genommen. Der Cluster erstellt ein Spiegelbild für jede Warteschlange auf dem neuen Knoten und synchronisiert automatisch die neue Warteschlange A mit dem Master. Das Spiegelbild der neuen Warteschlange B bleibt jedoch leer. Damit haben wir eine vollständige Redundanz der Warteschlange A und nur ein Spiegelbild für die bestehenden Nachrichten der Warteschlange B.

Abb. 10. Das neue Spiegelbild der Warteschlange A erhält alle vorhandenen Nachrichten, das neue Spiegelbild der Warteschlange B jedoch nicht
In beiden Warteschlangen kommen jeweils weitere zehn Nachrichten an. Dann fällt Broker 2 aus, und Warteschlange A wird auf das älteste Spiegelbild zurückgesetzt, das sich auf Broker 1 befindet. Bei einem Ausfall kommt es zu keinem Datenverlust. In Warteschlange B sind zwanzig Nachrichten im Master und nur zehn im Spiegelbild, da diese Warteschlange die ursprünglichen zehn Nachrichten nie repliziert hat.

Abb. 11. Warteschlange A wird von Broker 1 ohne Nachrichtenverlust zurückgesetzt
In beiden Warteschlangen gehen jeweils zehn Nachrichten ein. Jetzt fällt Broker 1 aus. Warteschlange A wechselt problemlos auf das Spiegel-System, ohne Nachrichten zu verlieren. Bei Warteschlange B gibt es jedoch Probleme. In diesem Stadium können wir entweder die Verfügbarkeit oder die Konsistenz optimieren.
Wenn wir die Verfügbarkeit optimieren möchten, sollte die Richtlinie ha-promote-on-failure auf always. Dies ist der Standardwert, sodass die Richtlinie einfach nicht angegeben werden kann. In diesem Fall erlauben wir im Wesentlichen Ausfälle bei nicht synchronisierten Spiegeln. Dies führt zum Verlust von Nachrichten, aber die Warteschlange bleibt weiterhin lesbar und beschreibbar.

Abb. 12. Warteschlange A wechselt zu Broker 3, ohne Nachrichten zu verlieren. Warteschlange B wechselt zu Broker 3 mit dem Verlust von zehn Nachrichten.
Wir können auch ha-promote-on-failure auf when-synced. In diesem Fall wird die Warteschlange nicht auf den Stand des Spiegels zurückgesetzt, sondern wartet darauf, dass Broker 1 mit seinen Daten wieder in den Betrieb zurückkehrt. Nach seiner Rückkehr erhält die Hauptwarteschlange wieder Zugang über Broker 1, ohne Datenverlust. Die Verfügbarkeit wird jedoch zugunsten der Datensicherheit geopfert. Aber dies ist ein riskanter Modus, der sogar zu einem vollständigen Datenverlust führen kann, was wir in Kürze besprechen werden.

Abb. 13. Die Warteschlange B bleibt nach dem Ausfall von Broker 1 nicht erreichbar.
Sie könnten die Frage stellen: „Vielleicht sollten wir die automatische Synchronisation nie verwenden?“. Die Antwort lautet, dass die Synchronisation eine blockierende Operation ist. Während der Synchronisation kann die Hauptwarteschlange keine Lese- oder Schreibvorgänge durchführen!
Schauen wir uns ein Beispiel an. Derzeit haben wir sehr große Warteschlangen. Wie können sie so groß werden? Aus mehreren Gründen:
- Die Warteschlangen werden nicht aktiv genutzt.
- Es handelt sich um Hochgeschwindigkeitswarteschlangen, aber zurzeit arbeiten die Verbraucher langsam.
- Es handelt sich um Hochgeschwindigkeitswarteschlangen, es gab einen Ausfall, und die Verbraucher holen auf.

Abb. 14. Zwei große Warteschlangen mit unterschiedlichen Synchronisationsmodi.
Broker 3 fällt nun aus.

Abb. 15. Broker 3 fällt aus und hinterlässt jeweils einen Master und ein Mirror in jeder Queue.
Broker 3 wird wieder aktiviert und neue Mirrors werden erstellt. Die Haupt-Queue A beginnt, vorhandene Nachrichten auf das neue Mirror zu replizieren, und in dieser Zeit ist die Queue nicht verfügbar. Die Datenreplikation benötigt zwei Stunden, was zu zwei Stunden Ausfallzeit für diese Queue führt!
Die Queue B bleibt jedoch während des gesamten Zeitraums verfügbar. Sie hat auf eine gewisse Redundanz verzichtet, um die Verfügbarkeit zu gewährleisten.

Abb. 16. Die Queue bleibt während der Synchronisation nicht verfügbar.
Nach zwei Stunden wird auch Queue A wieder verfügbar und kann erneut Lese- und Schreiboperationen annehmen.
Updates
Ein solches blockierendes Verhalten während der Synchronisierung erschwert die Aktualisierung von Clustern mit sehr großen Warteschlangen. Irgendwann muss der Knoten mit dem Master neu gestartet werden, was entweder einen Wechsel zu einem Spiegel oder das Deaktivieren der Warteschlange während des Server-Updates bedeutet. Wenn wir uns für den Wechsel entscheiden, verlieren wir Nachrichten, falls die Spiegel nicht synchronisiert sind. Standardmäßig wird beim Deaktivieren des Brokers kein Wechsel zu einem nicht synchronisierten Spiegel durchgeführt. Das bedeutet, dass wir, sobald der Broker wieder online ist, keine Nachrichten verlieren; der einzige Nachteil ist der einfache Warteschlangenstillstand. Die Verhaltensregeln beim Deaktivieren des Brokers werden durch die Richtlinie festgelegt. ha-promote-on-shutdown. Es kann einer von zwei Werte gesetzt werden:
always= Wechsel zu nicht synchronisierten Spiegeln aktiviertwhen-synced= Wechsel nur zu synchronisierten Spiegeln, andernfalls wird die Warteschlange für Lese- und Schreibzugriffe nicht verfügbar. Die Warteschlange wird wieder betriebsbereit, sobald der Broker zurückkehrt.
So oder so muss man bei großen Warteschlangen zwischen Datenverlust und Nichtverfügbarkeit wählen.
Wenn die Verfügbarkeit erhöht wird, steigt die Datensicherheit.
Bevor Sie eine Entscheidung treffen, sollte noch ein weiteres Komplikation berücksichtigt werden. Obwohl die automatische Synchronisierung für Redundanz besser ist, wie beeinflusst sie die Datensicherheit? Sicherlich verringert die bessere Redundanz von RabbitMQ die Wahrscheinlichkeit, vorhandene Nachrichten zu verlieren, aber wie steht es um neue Nachrichten von Publishern?
Folgendes sollte berücksichtigt werden:
- Kann der Publisher einfach einen Fehler zurückgeben, und wird der übergeordnete Dienst oder der Benutzer später einen erneuten Versuch unternehmen?
- Kann der Publisher die Nachricht lokal oder in einer Datenbank speichern, um es später erneut zu versuchen?
Wenn der Publisher lediglich in der Lage ist, die Nachricht abzulehnen, erhöht die Verbesserung der Verfügbarkeit tatsächlich auch die Datensicherheit.
Daher ist es notwendig, ein Gleichgewicht zu finden, und die Entscheidung hängt von der spezifischen Situation ab.
Probleme mit ha-promote-on-failure=when-synced
Die Idee ha-promote-on-failure= when-synced besteht darin, dass wir den Wechsel zu einem nicht synchronisierten Spiegel verhindern und dadurch Datenverluste vermeiden. Die Warteschlange bleibt für Lese- oder Schreibvorgänge unzugänglich. Stattdessen versuchen wir, den ausgefallenen Broker mit intakten Daten wiederherzustellen, damit er ohne Datenverlust wieder als Master arbeiten kann.
Aber (und das ist ein großes Aber), wenn der Broker seine Daten verloren hat, haben wir ein großes Problem: Die Warteschlange ist verloren! Alle Daten sind weg! Selbst wenn Sie Spiegel haben, die im Wesentlichen die Hauptwarteschlange einholen, werden auch diese Spiegel verworfen.
Um einen Knoten mit demselben Namen erneut hinzuzufügen, sagen wir dem Cluster, dass es den verlorenen Knoten vergessen soll (mit dem Befehl rabbitmqctl forget_cluster_node) und starten einen neuen Broker mit demselben Hostnamen. Solange das Cluster sich an den verlorenen Knoten erinnert, sind die alte Warteschlange und die nicht synchronisierten Spiegel bekannt. Wenn dem Cluster gesagt wird, den verlorenen Knoten zu vergessen, wird auch diese Warteschlange vergessen. Jetzt muss sie erneut deklariert werden. Wir haben alle Daten verloren, auch wenn wir Spiegel mit einem teilweisen Datensatz hatten. Es wäre besser gewesen, auf einen nicht synchronisierten Spiegel umzuschalten!
Deshalb ist die manuelle Synchronisierung (und das Unterlassen der Synchronisierung) in Kombination mit ha-promote-on-failure=when-synced, meiner Meinung nach, ziemlich riskant. Die Dokumente besagen, dass diese Option zur Datensicherheit existiert, aber sie ist ein zweischneidiges Schwert.
Neuverteilung der Master
Wie versprochen, kehren wir zum Problem der Ansammlung aller Master auf einem oder mehreren Knoten zurück. Dies kann sogar durch ein „Rolling“ Update des Clusters geschehen. In einem Cluster mit drei Knoten werden alle Hauptwarteschlangen sich auf einem oder zwei Knoten sammeln.
Die Neuverteilung der Master kann aus zwei Gründen problematisch sein:
- Es gibt keine guten Werkzeuge zur Durchführung der Neuverteilung.
- Synchronisierung der Warteschlangen
Für die Neuverteilung gibt es ein Drittanbieter- , das nicht offiziell unterstützt wird. Zum Thema Drittanbieter-Plugins steht im RabbitMQ-Handbuch : „Das Plugin bietet einige zusätzliche Anpassungs- und Berichtswerkzeuge, wird jedoch nicht unterstützt und nicht von der RabbitMQ-Community überprüft. Nutzen Sie es auf eigenes Risiko.“
Es gibt noch einen weiteren Trick, um die Hauptwarteschlange über HA-Richtlinien zu verschieben. Im Handbuch wird darauf hingewiesen dafür. Es funktioniert wie folgt:
- Entfernt alle Spiegel mithilfe einer temporären Richtlinie mit höherer Priorität als die vorhandene HA-Richtlinie.
- Ändert die temporäre HA-Richtlinie, um den Modus „Knoten“ mit dem Knoten anzugeben, auf den die Hauptwarteschlange verschoben werden soll.
- Synchronisiert die Warteschlange zur erzwungenen Migration.
- Nach Abschluss der Migration wird die temporäre Richtlinie gelöscht. Die ursprüngliche HA-Richtlinie tritt in Kraft, und die erforderliche Anzahl von Spiegeln wird erstellt.
Der Nachteil ist, dass dieser Ansatz möglicherweise nicht funktioniert, wenn Sie große Warteschlangen oder strenge Redundanzanforderungen haben.
Nun sehen wir, wie RabbitMQ-Cluster mit Netzwerkpartitionen umgehen.
Verletzung der Konsistenz
Die Knoten eines verteilten Systems sind durch Netzwerkverbindungen verbunden, und diese Verbindungen können unterbrochen werden. Die Häufigkeit der Unterbrechungen hängt von der lokalen Infrastruktur oder der Zuverlässigkeit der gewählten Cloud ab. In jedem Fall sollten verteilte Systeme in der Lage sein, damit umzugehen. Wiedermal stehen wir vor der Wahl zwischen Verfügbarkeit und Konsistenz, und erneut ist die gute Nachricht, dass RabbitMQ beide Optionen bereitstellt (aber nicht gleichzeitig).
Mit RabbitMQ haben wir zwei Hauptoptionen:
- Ermöglichen Sie eine logische Trennung (Split-Brain). Dies gewährleistet Verfügbarkeit, kann jedoch zu Datenverlust führen.
- Verhindern Sie eine logische Trennung. Dies kann je nach Art der Verbindung der Clients mit dem Cluster zu kurzfristigem Verlust der Verfügbarkeit führen. Außerdem kann es in einem Cluster mit zwei Knoten zu vollständiger Unverfügbarkeit führen.
Aber was ist eine logische Trennung? Dies geschieht, wenn der Cluster aufgrund eines Verlusts der Netzwerkverbindungen in zwei Teile geteilt wird. Auf jeder Seite wird das Spiegelbild zu einem Master, sodass letztendlich auf jede Warteschlange mehrere Master kommen.

Abb. 17. Die Hauptwarteschlange und zwei Spiegel, jeweils auf einem separaten Knoten. Dann tritt ein Netzwerkfehler auf, und ein Spiegel wird getrennt. Der getrennte Knoten erkennt, dass die beiden anderen ausgefallen sind, und befördert seine Spiegel zum Master. Jetzt haben wir zwei Hauptwarteschlangen, die beide Schreib- und Lesezugriff ermöglichen.
Wenn Publisher Daten an beide Master senden, erhalten wir zwei divergierende Kopien der Warteschlange.
Die verschiedenen Modi von RabbitMQ bieten entweder Verfügbarkeit oder Konsistenz.
Ignorieren-Modus (Standard)
Dieser Modus gewährleistet Verfügbarkeit. Nach dem Verlust der Konnektivität tritt eine logische Trennung ein. Nach der Wiederherstellung der Konnektivität muss der Administrator entscheiden, welchem Abschnitt der Vorzug gegeben wird. Die unterlegene Seite wird neu gestartet, und alle gespeicherten Daten auf dieser Seite gehen verloren.

Abb. 18. Drei Publisher sind mit drei Brokern verbunden. Intern leitet das Cluster alle Anfragen an die Hauptwarteschlange auf Broker 2.
Jetzt verlieren wir Broker 3. Er erkennt, dass die anderen Broker ausgefallen sind, und befördert seinen Spiegel zum Master. So tritt eine logische Trennung ein.

Abb. 19. Logische Trennung (Split-Brain). Die Einträge gehen in zwei Hauptwarteschlangen, und zwei Kopien gehen auseinander.
Die Verbindung wird wiederhergestellt, aber die logische Trennung bleibt bestehen. Der Administrator muss manuell die unterlegene Seite auswählen. Im folgenden Fall startet der Administrator Broker 3 neu. Alle Nachrichten, die nicht übermittelt werden konnten, gehen verloren.

Abb. 20. Der Administrator trennt Broker 3.

Abb. 21. Der Administrator startet Broker 3, und er verbindet sich mit dem Cluster und verliert dabei alle Nachrichten, die dort verblieben sind.
Während der Verlust der Verbindung und nach ihrer Wiederherstellung waren der Cluster und diese Warteschlange zum Lesen und Schreiben verfügbar.
Autoheal-Modus
Funktioniert ähnlich wie der Ignorieren-Modus, mit dem Unterschied, dass der Cluster automatisch die unterlegene Seite nach der Trennung und Wiederherstellung der Verbindung auswählt. Die unterlegene Seite kehrt leer in den Cluster zurück, und die Warteschlange verliert alle Nachrichten, die nur an diese Seite gesendet wurden.
Pause-Minority-Modus
Wenn wir eine logische Trennung vermeiden möchten, bleibt uns nur die Möglichkeit, das Lesen und Schreiben auf der kleineren Seite nach der Partition des Clusters abzulehnen. Wenn der Broker erkennt, dass er sich auf der kleineren Seite befindet, stoppt er seine Arbeit, schließt also alle bestehenden Verbindungen und lehnt alle neuen ab. Einmal pro Sekunde überprüft er die Wiederherstellung der Konnektivität. Sobald die Konnektivität wiederhergestellt ist, setzt er seine Arbeit fort und verbindet sich wieder mit dem Cluster.

Abb. 22. Drei Publisher sind mit drei Brokern verbunden. Intern leitet der Cluster alle Anfragen an die Hauptwarteschlange bei Broker 2.
Dann trennen sich Broker 1 und 2 von Broker 3. Anstatt sein Spiegelbild zum Master zu erhöhen, stoppt Broker 3 die Arbeit und wird nicht mehr verfügbar.

Abb. 23. Broker 3 stoppt die Arbeit, trennt alle Kunden und lehnt Verbindungsgesuche ab.
Sobald die Konnektivität wiederhergestellt ist, kehrt er in den Cluster zurück.
Sehen wir uns ein anderes Beispiel an, bei dem die Hauptwarteschlange bei Broker 3 ist.

Abb. 24. Die Hauptwarteschlange befindet sich bei Broker 3.
Dann tritt derselbe Verlust der Konnektivität ein. Broker 3 wird in den Standby-Modus versetzt, da er sich auf der kleineren Seite befindet. Auf der anderen Seite sehen die Knoten, dass Broker 3 ausgefallen ist, und somit wird das ältere Spiegelbild von Broker 1 und 2 zum Master hochgestuft.

Abb. 25. Wechsel zu Broker 2 bei Nichterreichbarkeit von Broker 3.
Sobald die Konnektivität wiederhergestellt ist, schließt sich Broker 3 dem Cluster an.

Abb. 26. Das Cluster arbeitet wieder normal.
Hier ist es wichtig zu verstehen, dass wir Konsistenz erreichen, aber auch Verfügbarkeit erhalten können, wenn wir die Clients erfolgreich auf den größeren Teil des Abschnitts umschalten. Für die meisten Situationen würde ich persönlich den Modus Pause Minority bevorzugen, aber das hängt wirklich vom konkreten Fall ab.
Um die Verfügbarkeit zu gewährleisten, ist es wichtig sicherzustellen, dass die Clients erfolgreich eine Verbindung zu einem Knoten herstellen. Lassen Sie uns unsere Optionen betrachten.
Sicherstellung der Klientenkonnektivität
Wir bieten mehrere Möglichkeiten, wie Sie nach einem Verbindungsverlust die Clients auf den Hauptteil des Clusters oder auf funktionierende Knoten umleiten können (nach einem Ausfall eines Knotens). Zunächst erinnern wir uns daran, dass eine bestimmte Warteschlange auf einem bestimmten Knoten platziert wird, jedoch die Routing- und Replikationsrichtlinien auf allen Knoten verteilt sind. Clients können sich mit jedem Knoten verbinden, und das interne Routing leitet sie entsprechend weiter. Wenn jedoch ein Knoten außer Betrieb ist, weist er Verbindungen zurück, sodass die Clients sich mit einem anderen Knoten verbinden müssen. Wenn ein Knoten ausfällt, kann er kaum etwas tun.
Unsere Optionen:
- Der Zugriff auf das Cluster erfolgt über einen Lastenausgleich, der die Knoten einfach zyklisch durchläuft, während die Clients Verbindungswiederholungen bis zum erfolgreichen Abschluss durchführen. Wenn ein Knoten nicht funktioniert oder außer Betrieb ist, werden die Verbindungsversuche zu diesem Knoten fehlschlagen, aber die nachfolgenden Versuche werden an andere Server (im Zyklenmodus) weitergeleitet. Dies eignet sich für kurzfristige Verbindungsverluste oder einen Serverausfall, der schnell behoben werden kann.
- Zugang zum Cluster über den Load Balancer und das Entfernen von inaktiven/ausgefallenen Knoten aus der Liste, sobald diese erkannt werden. Wenn dies schnell geschieht und die Kunden in der Lage sind, erneut zu verbinden, gewährleisten wir eine durchgehende Verfügbarkeit.
- Jedem Kunden eine Liste aller Knoten zur Verfügung stellen, aus der er beim Verbindungsaufbau zufällig einen auswählt. Wenn er beim Verbindungsversuch einen Fehler erhält, wechselt er zum nächsten Knoten in der Liste, bis die Verbindung hergestellt ist.
- Den Verkehr von einem ausgefallenen/inaktiven Knoten über DNS umleiten. Dies erfolgt durch einen kurzen TTL.
Fazit
Die Clusterbildung von RabbitMQ hat ihre eigenen Vor- und Nachteile. Die gravierendsten Nachteile sind:
- bei der Verbindung zum Cluster verwerfen die Knoten ihre Daten;
- blockierende Synchronisation führt zur Nichterreichbarkeit der Warteschlange.
Alle schwierigen Entscheidungen resultieren aus diesen beiden Eigenschaften der Architektur. Wenn RabbitMQ Daten beim Wiederverbinden des Clusters speichern könnte, würde die Synchronisation schneller erfolgen. Wenn es in der Lage wäre, nicht-blockierende Synchronisation zu unterstützen, könnte es große Warteschlangen besser verwalten. Die Behebung dieser beiden Probleme würde die Leistung von RabbitMQ als ausfallsichere und hochverfügbare Messaging-Technologie erheblich verbessern. Ich würde nicht empfehlen, RabbitMQ mit Clusterbildung in den folgenden Situationen einzusetzen:
- Unzuverlässiges Netzwerk.
- Unzuverlässiger Speicher.
- Sehr große Warteschlangen.
Was die Einstellungen für hohe Verfügbarkeit betrifft, so ziehen Sie Folgendes in Betracht:
ha-promote-on-failure=alwaysha-sync-mode=manualcluster_partition_handling=ignore(oderautoheal)- ausfallsichere Nachrichten
- stellen Sie sicher, dass Clients sich mit einem aktiven Knoten verbinden, wenn ein Knoten ausfällt.
Für Konsistenz (Datensicherheit) ziehen Sie die folgenden Einstellungen in Betracht:
- Publisher Confirms und manuelle Bestätigungen auf der Verbraucherseite
ha-promote-on-failure=when-synced, wenn die Publisher später erneut versuchen können und wenn Sie sehr zuverlässigen Speicher haben! Andernfalls setzen Sie=always.ha-sync-mode=automatic(aber für große inaktive Warteschlangen kann der manuelle Modus erforderlich sein; zudem sollten Sie überlegen, ob eine Nichtverfügbarkeit zu Nachrichtenverlust führen könnte)- Pause-Minderheitenmodus
- ausfallsichere Nachrichten
Wir haben noch nicht alle Fragen zur Fehlertoleranz und Hochverfügbarkeit behandelt; zum Beispiel, wie man Verwaltungsverfahren sicher durchführt (wie gleitende Aktualisierungen). Wir müssen auch über Föderation und das Shovel-Plugin sprechen.
Falls ich noch etwas übersehen habe, lassen Sie es mich bitte wissen.
Siehe auch meinen , in dem ich einen Angriff auf ein RabbitMQ-Cluster mit Docker und Blockade durchführe, um einige in diesem Artikel beschriebene Szenarien zum Nachrichtenverlust zu testen.
Vorangegangene Artikel der Serie:
Nr. 1 —
Nr. 2 —
Nr. 3 —
Quelle: habr.com
