Best Practices für das RabbitMQ-Speichermanagement und hohen Durchsatz

Stimmen Sie RabbitMQ-Speicher, Festplattenlimits, Warteschlangen und Verbraucher so ab, dass hoher Durchsatz nicht zu Broker-Druck wird.

Best Practices für das RabbitMQ-Speichermanagement und hohen Durchsatz

RabbitMQ kann viele Nachrichten bewegen, aber es ist nicht glücklich, wenn der Speicher zum Überlaufplan wird. Der Broker benötigt Speicher für Verbindungen, Kanäle, Warteschlangenprozesse, Nachrichtenmetadaten, nicht bestätigte Zustellungen, Plugins, Metriken und die Erlang-Laufzeit selbst. Wenn Publisher für lange Zeit schneller sind als Verbraucher, stellt sich nicht mehr die Frage "Wie schnell kann RabbitMQ gehen?", sondern "Wo zeigt sich der Druck zuerst?"

Gutes Speichermanagement besteht hauptsächlich darin, diesen Druck sichtbar und kontrolliert zu halten. Sie möchten, dass RabbitMQ Gegendruck ausübt, bevor das Betriebssystem beginnt, Prozesse zu beenden. Sie möchten auch genügend Festplattenspielraum, damit persistente Nachrichten und interner Zustand sicher geschrieben werden können.

Beginnen Sie mit dem Speicheralarm, aber behandeln Sie ihn nicht als Tuning-Magie

RabbitMQ verwendet vm_memory_high_watermark, um zu entscheiden, wann die Speichernutzung zu hoch ist. Wenn der Schwellenwert überschritten wird, löst RabbitMQ einen Speicheralarm aus und blockiert Publisher, bis der Speicher fällt. Dieses Verhalten ist beabsichtigt. Ein blockierter Publisher ist ärgerlich; ein Broker ohne Speicher ist schlimmer.

Ein üblicher Ausgangspunkt ist ein relativer Wasserstand von etwa 40 % des verfügbaren Speichers:

vm_memory_high_watermark.relative = 0.40

Diese Zahl ist nicht in Stein gemeißelt. Eine kleine VM mit anderen Diensten benötigt möglicherweise einen niedrigeren Schwellenwert. Ein dedizierter Broker mit gut verstandenen Arbeitslasten kann einen anderen Wert tolerieren. Der Punkt ist, Platz für den OS-Page-Cache, Dateisystemaktivitäten, Überwachungsagenten und Spitzen zu lassen, die auftreten, bevor Ihre Graphen nachziehen.

Sie können auch einen absoluten Wert festlegen, der in Containern oder Umgebungen, in denen "verfügbarer Speicher" missverstanden werden kann, oft einfacher ist:

vm_memory_high_watermark.absolute = 6GiB

Verwenden Sie einen Stil, der zur Bereitstellung des Knotens passt. Überprüfen Sie in Containern, ob RabbitMQ das von Ihnen erwartete Container-Limit sieht, nicht den gesamten Speicher des Hosts. Ein Wasserstand, der auf der falschen Speichergesamtmenge basiert, ist eine leise Art, einen Produktionsvorfall zu verursachen.

Das Festplattenfreigrenze ist die andere Sicherheitsschiene

RabbitMQs Festplattenschutzeinstellung ist disk_free_limit. Sie basiert auf freiem Speicherplatz, nicht auf einem disk_high_watermark-Prozentsatz. Wenn der freie Festplattenspeicher unter das konfigurierte Limit fällt, löst RabbitMQ einen Festplattenalarm aus und blockiert Publisher.

Für viele Produktionsknoten ist ein absolutes Limit klarer als ein relatives:

disk_free_limit.absolute = 20GB

Der richtige Wert hängt von der Nachrichtengröße, der Veröffentlichungsrate, der Persistenz, der Log-Rotation und davon ab, wie schnell Ihr Team Speicherplatz hinzufügen oder Warteschlangen leeren kann. Ein Knoten, der große persistente Nachrichten empfängt, benötigt ein viel größeres Polster als ein Knoten, der winzige flüchtige Ereignisse verarbeitet.

Setzen Sie dies nicht auf einen winzigen Wert, nur um Alarme zu vermeiden. Festplattenalarme dienen dem Schutz des Brokers. Wenn eine Festplatte null freie Bytes erreicht, können fehlgeschlagene Schreibvorgänge, beschädigte Verfügbarkeit und eine viel chaotischere Wiederherstellung die Folge sein.

Verstehen Sie, was tatsächlich Speicher verwendet

Wenn der Speicher steigt, vermeiden Sie Raten. RabbitMQ legt eine Speicheraufschlüsselung über die Verwaltungsoberfläche und CLI offen:

rabbitmq-diagnostics memory_breakdown
rabbitmqctl status
rabbitmqctl list_queues name type messages_ready messages_unacknowledged memory

Die nützlichste erste Aufteilung ist zwischen bereiten Nachrichten und nicht bestätigten Nachrichten. Bereite Nachrichten warten noch in der Warteschlange. Nicht bestätigte Nachrichten wurden an Verbraucher zugestellt und warten auf basic.ack, basic.nack oder Kanalschließung.

Wenn bereite Nachrichten steigen, überholen Produzenten die Verbraucher oder Verbraucher sind nicht verbunden. Wenn nicht bestätigte Nachrichten steigen, nehmen Verbraucher Nachrichten entgegen, beenden sie aber nicht. Das sind unterschiedliche Probleme. Das Erhöhen von Speichergrenzen verschafft nur Zeit, wenn das Flussungleichgewicht bestehen bleibt.

Große Nachrichten verdienen besondere Aufmerksamkeit. Eine Warteschlange mit bescheidenen Nachrichtenzahlen kann dennoch viel Speicher verbrauchen, wenn jede Nachricht eine große Nutzlast trägt. Wenn Nachrichten Bilder, Dokumente oder große JSON-Blobs enthalten, erwägen Sie, die Nutzlast woanders zu speichern und einen Verweis durch RabbitMQ zu senden. Nachrichtenbroker sind normalerweise besser darin, Arbeitsbenachrichtigungen zu verschieben, als als Blob-Speicher zu fungieren.

Optimieren Sie Prefetch, um versteckte Rückstände zu stoppen

Prefetch steuert, wie viele nicht bestätigte Nachrichten RabbitMQ an einen Verbraucher ausliefern kann. Ein hoher Prefetch-Wert kann den Durchsatz für schnelle Verbraucher verbessern, verschiebt aber auch den Rückstand aus der Warteschlange in den Speicher des Verbrauchers.

Zum Beispiel können zehn Verbraucher mit prefetch_count=500 bis zu 5.000 nicht bestätigte Nachrichten außerhalb der Bereit-Warteschlange halten. Wenn jede Nachricht groß oder langsam zu verarbeiten ist, kann dies Speicherdruck und ungleichmäßige Latenz erzeugen. Eine neue Nachricht kann hinter Hunderten älterer Nachrichten warten, die bereits in einem langsamen Verbraucher sitzen.

Beginnen Sie mit einem Prefetch-Wert, der zur Arbeit passt. Für langsame API-Aufrufe oder Datenbankschreibvorgänge versuchen Sie eine kleine Zahl wie 5 oder 10 und erhöhen Sie erst nach Messung. Für sehr schnelle lokale CPU-Arbeit können höhere Werte helfen. Für strikte Fairness ist prefetch_count=1 manchmal der richtige Kompromiss, auch wenn der Gesamtdurchsatz niedriger ist.

Der Schlüssel ist, die Verarbeitungszeit und die Verzögerung der Bestätigung zu messen. RabbitMQ kann Nachrichten nicht für Sie beenden. Es kann nur begrenzen, wie viel unerledigte Arbeit es ausgibt.

Halten Sie Warteschlangen nach Möglichkeit kurz

RabbitMQ funktioniert am besten, wenn Nachrichten durch das System fließen, anstatt stundenlang in Warteschlangen zu sitzen. Eine Warteschlange, die normalerweise nahe Null ist und gelegentlich ansteigt, ist gesund. Eine Warteschlange, die den ganzen Tag wächst und über Nacht abfließt, ist eine Kapazitätswarnung. Eine Warteschlange, die nur wächst, ist ein Ausfall in Zeitlupe.

Für lange Rückstände entscheiden Sie, ob der Rückstand erwartet wird. Wenn er erwartet wird, verwenden Sie den Warteschlangentyp und das Speicherdesign, das passt. Quorum-Warteschlangen sind gut für dauerhafte replizierte Arbeitslasten. Streams können für Wiedergabe-Workloads geeignet sein. Klassische Warteschlangen können für einfachere flüchtige Arbeiten in Ordnung sein. Wenn der Rückstand nicht erwartet wird, beheben Sie Verbraucher oder nachgelagerte Dienste, bevor Sie den Broker-Speicher optimieren.

Setzen Sie Nachrichten-TTLs nur, wenn abgelaufene Arbeit wirklich nutzlos ist. Eine TTL ist kein Ersatz für Kapazität. Sie kann ein System davor schützen, veraltete Nachrichten zu verarbeiten, kann aber auch Datenverlust verbergen, wenn sie beiläufig angewendet wird.

Dead-Letter-Warteschlangen helfen, Giftnachrichten vom normalen Fluss zu trennen. Ohne eine Dead-Letter-Strategie kann eine schlechte Nutzlast für immer wiederholt werden, Ressourcen verbrauchen und die Warteschlange langsamer erscheinen lassen, als sie wirklich ist.

Persistenz ändert das Durchsatzbudget

Dauerhafte Warteschlangen und persistente Nachrichten sind die richtige Wahl, wenn Nachrichten einen Broker-Neustart überleben müssen. Sie erfordern auch Festplattenschreibvorgänge. Publisher-Bestätigungen fügen ein Zuverlässigkeitssignal hinzu, damit Publisher wissen, wann der Broker die Verantwortung für eine Nachricht übernommen hat.

Das langsame Muster ist, eine persistente Nachricht zu veröffentlichen, synchron auf ihre Bestätigung zu warten und dann die nächste zu veröffentlichen. Es ist einfach und sicher, aber der Durchsatz wird durch die Round-Trip-Zeit und das Festplattenverhalten begrenzt. Ein besseres Muster ist die Verwendung asynchroner Publisher-Bestätigungen oder kleiner Stapel, während negative Bestätigungen und Timeouts behandelt werden.

Vermeiden Sie AMQP-Transaktionen für das Veröffentlichen mit hohem Durchsatz, es sei denn, Sie haben einen sehr spezifischen Grund. Publisher-Bestätigungen sind das übliche Zuverlässigkeitswerkzeug für RabbitMQ-Publisher.

Geben Sie RabbitMQ langweilige Infrastruktur

RabbitMQ mag vorhersehbare Maschinen: genügend Speicher, schnelle Festplatten für persistente Arbeitslasten, stabile Netzwerklatenz und keinen lauten Nachbarn, der CPU stiehlt. Wenn der Broker einen Host mit einer Datenbank, einem Log-Prozessor und zufälligen Cron-Jobs teilt, wird die Speicheroptimierung zum Ratespiel.

Verwenden Sie SSD- oder NVMe-Speicher für persistente Warteschlangen mit hohem Durchsatz. Überwachen Sie die Festplattenlatenz, nicht nur die Festplattenauslastung. Eine Festplatte kann moderaten Durchsatz zeigen und dennoch schmerzhafte Schreiblatenz aufweisen. In Cloud-Umgebungen können bereitgestellte IOPS und Burst-Guthaben wichtiger sein als die Festplattenbezeichnung.

Begrenzen Sie den Verbindungswechsel. Langlebige Verbindungen und Kanäle sind günstiger als das Öffnen neuer für jede Veröffentlichung. Wenn eine Anwendung Tausende kurzlebiger Verbindungen erstellt, können Speicher- und Dateideskriptornutzung steigen, selbst wenn die Nachrichtenraten gewöhnlich sind.

Container benötigen explizites Denken

RabbitMQ läuft gut in Containern, aber Speichergrenzen müssen klar sein. Der Speicherwasserstand des Brokers ist nur nützlich, wenn er gegen das Limit berechnet wird, das der Container tatsächlich nutzen kann. Wenn RabbitMQ denkt, es habe den Speicher des Hosts, aber die Container-Laufzeit erzwingt ein kleineres Limit, kann der Container getötet werden, bevor RabbitMQs eigenes Alarmverhalten es schützt.

Setzen Sie ein Container-Speicherlimit und dann einen absoluten RabbitMQ-Wasserstand, der innerhalb dieses Limits Platz lässt:

vm_memory_high_watermark.absolute = 3GiB

Zum Beispiel kann auf einem Container, der auf 4 GiB begrenzt ist, ein Broker-Wasserstand von 3 GiB für einen dedizierten Pod angemessen sein, während ein niedrigerer Wert besser sein kann, wenn Sidecars oder Plugins bedeutenden Speicher verwenden. Kopieren Sie diese Zahl nicht blind. Der Punkt ist, die Beziehung explizit zu machen.

Persistente Daten benötigen auch persistenten Speicher. Wenn ein Container-Neustart das RabbitMQ-Datenverzeichnis verliert, werden dauerhafte Warteschlangen und persistente Nachrichten Sie nicht retten. Verwenden Sie geeignete Volumes, verstehen Sie Ihre Speicherklasse und testen Sie einen Broker-Neustart, bevor Sie dem Setup vertrauen.

Lazy-Warteschlangen, Quorum-Warteschlangen und Speichererwartungen

Ältere RabbitMQ-Ratschläge sagen oft "Verwenden Sie Lazy-Warteschlangen für große Rückstände." Dieser Rat benötigt Kontext. Klassische Lazy-Warteschlangen wurden entwickelt, um mehr Nachrichten auf der Festplatte zu halten und den Speicherdruck für lange Warteschlangen zu reduzieren. Sie können immer noch für klassische Warteschlangen-Workloads nützlich sein, bei denen große Rückstände erwartet werden.

Quorum-Warteschlangen verhalten sich anders und werden häufig für replizierte dauerhafte Arbeitslasten verwendet. Sie können Rückstände bewältigen, replizieren aber auch Daten und haben ihr eigenes Speicher- und Festplattenprofil. Eine Quorum-Warteschlange ist zuerst eine Zuverlässigkeitswahl. Sie ist keine Abkürzung für unbegrenzten Rückstand.

Wenn das Geschäft erwartet, dass Nachrichten tagelang sitzen und von vielen Verbrauchern wiedergegeben werden, passt ein Stream oder ein anderes Log-Stil-System möglicherweise besser als eine normale Arbeitswarteschlange. RabbitMQ ist hervorragend darin, Arbeit zu verteilen. Es ist weniger angenehm, wenn es die einzige Langzeitspeicherschicht für große historische Nutzlasten wird.

Trennen Sie Broker-Symptome von Arbeitslast-Symptomen

Ein Speicheralarm sagt Ihnen, dass RabbitMQ unter Druck steht. Er sagt Ihnen nicht, ob RabbitMQ die Ursache ist. Eine langsame Abrechnungs-API kann dazu führen, dass Verbraucher aufhören zu bestätigen, was nicht bestätigte Nachrichten steigen lässt, was den Broker-Speicher erhöht, was Publisher blockiert. Der Broker-Alarm ist real, aber die erste Lösung kann außerhalb des Brokers liegen.

Während einer Überprüfung graphisch darstellen: Veröffentlichungsrate, Zustellrate, Bestätigungsrate, bereite Nachrichten, nicht bestätigte Nachrichten, Speicher, freier Festplattenspeicher und Verarbeitungszeit der Verbraucher zusammen. Die Reihenfolge der Bewegung ist wichtig. Wenn die Bestätigungsrate fällt, bevor der Speicher steigt, schauen Sie auf die Verbraucher. Wenn die Festplattenlatenz ansteigt, bevor Bestätigungen langsamer werden, schauen Sie auf den Speicher. Wenn sich die Veröffentlichungsrate nach einer Produkteinführung verdoppelt, schauen Sie auf Kapazität und Gegendruck.

Deshalb sollten Lasttests auch Verbraucher und nachgelagerte Abhängigkeiten umfassen. Ein reiner Veröffentlichungs-Benchmark beweist sehr wenig über einen echten Workflow. Der Broker kann Nachrichten eine Weile schnell annehmen, aber das System funktioniert nur, wenn Verbraucher sie mit der erforderlichen Rate beenden.

Machen Sie Gegendruck für Anwendungsteams sichtbar

Das Blockieren von Publishern sollte nicht unsichtbar sein. Anwendungen sollten blockierte und entsperrte Verbindungsereignisse protokollieren, wenn die Client-Bibliothek sie bereitstellt, und Publisher sollten Timeouts für Veröffentlichungspfade haben, die benutzerseitige Anfragen speisen.

Ohne diese Sichtbarkeit wird ein Speicheralarm zu einer vagen Beschwerde "Die App ist langsam". Damit kann das Team sehen, dass RabbitMQ zu einem bestimmten Zeitpunkt Gegendruck ausgeübt hat, und dann diesen Zeitstempel mit der Warteschlangentiefe, Verbraucherfehlern, Festplattenlatenz und Bereitstellungsereignissen vergleichen.

Was ich während einer Überprüfung mit hohem Durchsatz prüfe

Ich beginne mit diesen Fragen:

  • Lösen Speicheralarme oder Festplattenalarme aus?
  • Sind Nachrichten meist bereit oder nicht bestätigt?
  • Welche Warteschlangen verwenden am meisten Speicher?
  • Halten Verbraucher mit der Veröffentlichungsrate Schritt?
  • Sind Publisher-Bestätigungen asynchron oder blockieren sie einzeln?
  • Sind Nachrichten größer als nötig?
  • Steigt die Festplattenlatenz während Spitzen?
  • Sind Verbindungen stabil oder ständig neu verbindend?

Diese Antworten weisen normalerweise auf die Lösung hin. Manchmal ist die Lösung eine Konfigurationsänderung. Häufiger ist es eine Flussänderung: schnellere Verbraucher, niedrigerer Prefetch, kleinere Nachrichten, bessere Stapelverarbeitung, ein Dead-Letter-Pfad oder ein Warteschlangentyp, der zur Arbeitslast passt.

Hoher Durchsatz ist nicht nur eine größere Zahl in einem Benchmark. Es ist die Fähigkeit, geschäftige Perioden zu absorbieren, ohne die Kontrolle über Speicher, Festplatte und Latenz zu verlieren. RabbitMQ gibt Ihnen die Sicherheitsschienen, aber Sie müssen den Verkehr dennoch in Bewegung halten.