Praktisch jede erfolgreiche Geschäftsanwendung erreicht irgendwann eine Phase, in der horizontale Skalierung erforderlich ist. In vielen Fällen kann einfach eine neue Instanz gestartet werden, um die durchschnittliche Last zu senken. Es gibt jedoch auch weniger triviale Fälle, in denen wir sicherstellen müssen, dass verschiedene Knoten voneinander wissen und die Arbeitslast sorgfältig verteilen.

Es kam sehr günstig, dass Erlang, das wir wegen seiner angenehmen Syntax und des Hypes darum gewählt haben, erstklassige . In der Theorie klingt das ganz trivial:
Der Nachrichtenaustausch zwischen Prozessen auf verschiedenen Knoten sowie zwischen Verweisen und Monitoren ist transparent […]
In der Praxis ist alles etwas komplizierter. Das Verteilte Erlang wurde entwickelt, als der Begriff „Container“ einfach eine große Metallkiste für den Transport bedeutete und „Docker“ nur ein Synonym für einen Hafenarbeiter war. Im IPv4 gab es viele ungenutzte Adressen, und Netzwerkunterbrechungen waren in der Regel auf von Nagetieren durchtrennte Kabel zurückzuführen, während die durchschnittliche Betriebszeit eines Produktionssystems in Jahrzehnten gemessen wurde.
Jetzt sind wir alle unvorstellbar autark, verpackt und betreiben ein verteiltes Erlang System in einer Umgebung, in der dynamische IP-Adressen nach dem Prinzip großer Zufälligkeit vergeben werden und Knoten nach Belieben des Planers erscheinen und verschwinden können. Um eine Flut von Standardcode in jedem Projekt, das ein verteiltes ErlangSystem betreibt, zu vermeiden, benötigt man Unterstützung.
Hinweis: Ich weiß, dass es gibt. Es ist wirklich großartig, hat über tausend Sterne, der Autor ist in der Community bekannt und so weiter. Wenn Ihnen die von diesem Paket angebotenen Methoden zur Erstellung und Verwaltung eines Clusters ausreichen – ich freue mich für Sie. Leider brauche ich viel mehr. Ich möchte die Konfiguration im Detail verwalten und nicht nur ein unbeteiligter Zuschauer im Theater der Cluster-Neugestaltung sein.
Anforderungen
Was ich persönlich brauchte, war eine Bibliothek, die das Management des Clusters übernimmt und folgende Eigenschaften aufweist:
- transparente Arbeit sowohl mit einer fest kodierten Liste von Knoten als auch mit dynamischer Erkennung über Dienste Erlang;
- vollständiges Callback bei jeder Änderung der Topologie (Knoten hierhin, Knoten dorthin, Netzwerkinstabilität, Splits);
- eine transparente Benutzeroberfläche zum Starten eines Clusters mit langen und kurzen Namen, ebenso wie mit
:nonode@nohost; - unterstützung für Docker direkt nach der Installation, ohne dass Infrastruktur-Code geschrieben werden muss.
Das bedeutet, dass ich, nachdem ich die Anwendung lokal getestet habe, :nonode@nohostoder in einer künstlich verteilten Umgebung mithilfe von , einfach ausführen möchte docker-compose up --scale my_app=3 und sehen möchte, wie es drei Instanzen in Docker ausführt, ohne dass Änderungen am Code notwendig sind. Ich möchte auch, dass abhängige Anwendungen, wie mnesia — wenn sich die Topologie ändert, den Cluster im Hintergrund live umkonfigurieren, ohne dass zusätzliche Eingriffe der Anwendung erforderlich sind.
Cloister war nicht als eine Bibliothek gedacht, die alles kann: von der Unterstützung für Cluster bis zum Kaffeekochen. Es ist keine universelle Lösung, die versucht, alle möglichen Anwendungsfälle abzudecken, oder die akademisch vollständige Lösung im Sinne der Theoretiker von CS Dieser Begriff wird investiert. Diese Bibliothek hat eine sehr präzise Zielsetzung, jedoch soll sie ihren nicht allzu umfangreichen Aufgabenumfang perfekt erfüllen. Dieses Ziel besteht darin, vollständige Transparenz zwischen der lokalen Entwicklungsumgebung und der verteilten elastischen Umgebung, die voll von feindlichen Containern ist, sicherzustellen.
Ausgewandter Ansatz
Cloister es ist vorgesehen, es als Anwendung zu starten, obwohl erfahrene Benutzer mit dem Zusammenstellen und der Wartung des Clusters manuell arbeiten können, indem sie es direkt starten Cloister.Manager im Baum der Supervisoren der Zielanwendung.
Beim Starten als Anwendung verlässt sich die Bibliothek auf config, von wo sie die folgenden Hauptwerte ausliest:
config :cloister,
otp_app: :my_app,
sentry: :"cloister.local", # oder ~w|n1@foo n2@bar|a
consensus: 3, # Anzahl der Knoten, die berücksichtigt werden sollen
# der Cluster ist aktiv
listener: MyApp.Listener # Listener, der aufgerufen wird, wenn
# der Ring sich geändert hatDie obigen Parameter bedeuten wörtlich Folgendes: Cloister wird für eine OTP-Anwendung verwendet :my_app, verwendet Erlang-Service Discovery um mindestens drei Knoten zu verbinden, und MyApp.Listener Modul (implementiert ) ist konfiguriert, um Benachrichtigungen über Änderungen der Topologie zu erhalten. Eine detaillierte Beschreibung der vollständigen Konfiguration finden Sie in .
Bei dieser Konfiguration startet die Anwendung Cloister es , indem der Startprozess der Hauptanwendung bis zum Erreichen eines Konsenses verschoben wird (drei Knoten sind verbunden und verknüpft, wie im obigen Beispiel dargestellt). Dies ermöglicht der Hauptanwendung anzunehmen, dass der Cluster bereits verfügbar ist, sobald sie gestartet wurde. Bei jeder Änderung der Topologie (und es wird viele davon geben, da die Knoten nicht vollständig synchron gestartet werden) wird der Handler . In den meisten Fällen führen wir eine Aktion durch, wenn wir eine Nachricht mit dem Status erhalten %Cloister.Monitor{status: :up}, was bedeutet: „Hallo, der Cluster ist zusammengestellt“.
In den meisten Fällen ist eine Einstellung von consensus: 3 optimal, da selbst wenn wir erwarten, dass mehr Knoten sich verbinden, der Callback durch status: :rehashing → status: :up auf jedem neu hinzugefügten oder entfernten Knoten geht.
Im Entwicklungsmodus reicht es aus, einfach consensus: 1 und Cloister zu setzen, um die Wartezeit beim Aufbauen des Clusters zu überspringen und zu sehen :nonode@nohost, oder :node@host, oder :node@host.domain — abhängig von der Konfiguration des Knotens (:none | :shortnames | :longnames).
Verwaltung verteilter Anwendungen
Verteilte Anwendungen entstehen normalerweise nicht im Vakuum und umfassen in der Regel auch abhängige Komponenten wie mnesia. Ihre Rekonfiguration lässt sich leicht über den gleichen Callback verarbeiten on_state_change/2. Hier ist beispielsweise eine detaillierte Beschreibung, wie man sie mnesia dynamisch rekonfiguriert in .
Der Hauptvorteil der Verwendung von Cloister besteht darin, dass alle notwendigen Operationen zur Umstrukturierung des Clusters nach einer Änderung der Topologie durchgeführt werden. unter der HaubeDie Anwendung wird einfach in der bereits vorbereiteten verteilten Umgebung gestartet, mit allen angeschlossenen Knoten, unabhängig davon, ob wir die IP-Adressen und somit die Knotennamen im Voraus kennen oder ob sie dynamisch zugewiesen/änderten wurden. Das erfordert keinerlei spezielle Docker-Konfiguration und aus Sicht des Anwendungsentwicklers gibt es keinen Unterschied zwischen der Ausführung in einer verteilten Umgebung oder lokal auf :nonode@nohost. Weitere Informationen dazu finden Sie in .
Obwohl eine komplexe Verarbeitung von Topologieänderungen durch eine eigene Implementierung möglich ist. MyApp.Listener, es kann immer Grenzfälle geben, in denen diese Bibliotheksbeschränkungen und eine voreingenommene Konfiguration zum entscheidenden Hindernis für die Implementierung werden. Das ist in Ordnung, nehmen Sie einfach die obige libcluster, die vielseitiger ist, oder verarbeiten Sie sogar einen Low-Level-Cluster selbst. Das Ziel dieser Codebibliothek ist nicht, alle möglichen Szenarien abzudecken, sondern das häufigste Szenario ohne unnötige Schmerzen und umständliches Copy-Paste zu nutzen.
Hinweis: An dieser Stelle stand im Original der Satz „Happy clustering!“, und Yandex, mit dem ich übersetze (ich werde ja nicht selbst in Wörterbüchern nachschlagen), hat mir die Variante „S glückliches Clustering!“ vorgeschlagen. Eine bessere Übersetzung ist wohl, besonders im Licht der aktuellen geopolitischen Situation, nicht vorstellbar.
Quelle: habr.com
