Ignite Service Grid – Neustart

Am 26. Februar veranstalteten wir ein Apache Ignite GreenSource-Treffen, bei dem Mitwirkende des Open-Source-Projekts sprachen Apache entzünden. Ein wichtiges Ereignis im Leben dieser Gemeinschaft war die Umstrukturierung der Komponente Zünden Sie das Servicenetz an, mit dem Sie benutzerdefinierte Microservices direkt in einem Ignite-Cluster bereitstellen können. Er sprach beim Treffen über diesen schwierigen Prozess Wjatscheslaw Daradur, Softwareentwickler und Apache Ignite-Mitarbeiter seit über zwei Jahren.

Ignite Service Grid – Neustart

Beginnen wir mit dem, was Apache Ignite im Allgemeinen ist. Dabei handelt es sich um eine Datenbank, bei der es sich um einen verteilten Schlüssel-/Wertspeicher mit Unterstützung für SQL, Transaktionalität und Caching handelt. Darüber hinaus können Sie mit Ignite benutzerdefinierte Dienste direkt in einem Ignite-Cluster bereitstellen. Der Entwickler hat Zugriff auf alle Tools, die Ignite bereitstellt – verteilte Datenstrukturen, Messaging, Streaming, Compute und Data Grid. Beispielsweise entfällt bei der Nutzung von Data Grid das Problem der Verwaltung einer separaten Infrastruktur zur Datenspeicherung und die damit verbundenen Gemeinkosten.

Ignite Service Grid – Neustart

Mithilfe der Service Grid-API können Sie einen Dienst bereitstellen, indem Sie einfach das Bereitstellungsschema und dementsprechend den Dienst selbst in der Konfiguration angeben.

Typischerweise ist ein Bereitstellungsschema ein Hinweis auf die Anzahl der Instanzen, die auf Clusterknoten bereitgestellt werden sollen. Es gibt zwei typische Bereitstellungsschemata. Der erste ist Cluster Singleton: Es ist garantiert, dass zu jedem Zeitpunkt eine Instanz eines Benutzerdienstes im Cluster verfügbar ist. Der zweite ist Node Singleton: Auf jedem Clusterknoten wird eine Instanz des Dienstes bereitgestellt.

Ignite Service Grid – Neustart

Der Benutzer kann außerdem die Anzahl der Service-Instanzen im gesamten Cluster angeben und ein Prädikat für die Filterung geeigneter Knoten definieren. In diesem Szenario berechnet Service Grid selbst die optimale Verteilung für die Bereitstellung von Diensten.

Darüber hinaus gibt es eine Funktion wie den Affinity Service. Affinität ist eine Funktion, die die Beziehung von Schlüsseln zu Partitionen und die Beziehung von Parteien zu Knoten in der Topologie definiert. Mithilfe des Schlüssels können Sie den primären Knoten bestimmen, auf dem die Daten gespeichert sind. Auf diese Weise können Sie Ihren eigenen Dienst einem Schlüssel- und Affinitätsfunktionscache zuordnen. Wenn sich die Affinitätsfunktion ändert, erfolgt eine automatische Neubereitstellung. Auf diese Weise befindet sich der Dienst immer in der Nähe der Daten, die er bearbeiten muss, und reduziert dementsprechend den Aufwand für den Zugriff auf Informationen. Dieses Schema kann als eine Art kolloziertes Rechnen bezeichnet werden.

Nachdem wir nun herausgefunden haben, was das Schöne an Service Grid ist, sprechen wir über seine Entwicklungsgeschichte.

Was war vorher

Die vorherige Implementierung von Service Grid basierte auf dem transaktional replizierten Systemcache von Ignite. Das Wort „Cache“ in Ignite bezieht sich auf Speicher. Das heißt, dies ist nicht etwas Vorübergehendes, wie Sie vielleicht denken. Trotz der Tatsache, dass der Cache repliziert wird und jeder Knoten den gesamten Datensatz enthält, verfügt er innerhalb des Caches über eine partitionierte Darstellung. Dies ist auf die Speicheroptimierung zurückzuführen.

Ignite Service Grid – Neustart

Was geschah, als der Benutzer den Dienst bereitstellen wollte?

  • Alle Knoten im Cluster haben sich angemeldet, um Daten im Speicher mithilfe des integrierten Mechanismus für kontinuierliche Abfragen zu aktualisieren.
  • Der initiierende Knoten hat im Rahmen einer Lese-Commit-Transaktion einen Datensatz in der Datenbank erstellt, der die Dienstkonfiguration einschließlich der serialisierten Instanz enthielt.
  • Bei der Benachrichtigung über einen neuen Eintrag berechnete der Koordinator die Verteilung anhand der Konfiguration. Das resultierende Objekt wurde in die Datenbank zurückgeschrieben.
  • Wenn ein Knoten Teil der Verteilung war, musste der Koordinator ihn bereitstellen.

Was uns nicht gepasst hat

Irgendwann kamen wir zu dem Schluss: So kann man mit Dienstleistungen nicht arbeiten. Es gab mehrere Gründe.

Wenn während der Bereitstellung ein Fehler aufgetreten ist, kann dies nur aus den Protokollen des Knotens herausgefunden werden, auf dem alles passiert ist. Es gab nur eine asynchrone Bereitstellung, sodass nach der Rückgabe der Kontrolle an den Benutzer von der Bereitstellungsmethode einige zusätzliche Zeit zum Starten des Dienstes erforderlich war – und während dieser Zeit konnte der Benutzer nichts steuern. Um das Service Grid weiterzuentwickeln, neue Funktionen zu schaffen, neue Benutzer zu gewinnen und das Leben aller einfacher zu machen, muss sich etwas ändern.

Bei der Konzeption des neuen Service Grids wollten wir zunächst eine synchrone Bereitstellung garantieren: Sobald der Benutzer die Kontrolle über die API zurückgibt, kann er die Dienste sofort nutzen. Ich wollte dem Initiator auch die Möglichkeit geben, mit Bereitstellungsfehlern umzugehen.

Darüber hinaus wollte ich die Implementierung vereinfachen, nämlich auf Transaktionen und Rebalancing verzichten. Trotz der Tatsache, dass der Cache repliziert wird und kein Ausgleich erfolgt, traten bei einer großen Bereitstellung mit vielen Knoten Probleme auf. Wenn sich die Topologie ändert, müssen Knoten Informationen austauschen, und bei einer großen Bereitstellung können diese Daten ein großes Gewicht haben.

Als die Topologie instabil war, musste der Koordinator die Verteilung der Dienste neu berechnen. Und wenn Sie mit Transaktionen in einer instabilen Topologie arbeiten müssen, kann dies im Allgemeinen zu schwer vorhersehbaren Fehlern führen.

Probleme

Was sind globale Veränderungen ohne begleitende Probleme? Die erste davon war eine Änderung der Topologie. Sie müssen verstehen, dass ein Knoten jederzeit, sogar zum Zeitpunkt der Dienstbereitstellung, in den Cluster eintreten oder ihn verlassen kann. Wenn der Knoten zum Zeitpunkt der Bereitstellung dem Cluster beitritt, ist es außerdem erforderlich, alle Informationen zu den Diensten konsistent auf den neuen Knoten zu übertragen. Und wir sprechen nicht nur über das, was bereits eingesetzt wurde, sondern auch über aktuelle und zukünftige Einsätze.

Dies ist nur eines der Probleme, die in einer separaten Liste zusammengefasst werden können:

  • Wie stellt man statisch konfigurierte Dienste beim Knotenstart bereit?
  • Einen Knoten aus dem Cluster entfernen – was tun, wenn der Knoten Dienste hostet?
  • Was tun, wenn der Koordinator gewechselt hat?
  • Was ist zu tun, wenn der Client erneut eine Verbindung zum Cluster herstellt?
  • Müssen Aktivierungs-/Deaktivierungsanfragen bearbeitet werden und wie?
  • Was wäre, wenn sie die Zerstörung des Caches fordern würden und wir damit verbundene Affinitätsdienste hätten?

Und das ist noch lange nicht alles.

Lösung

Als Ziel wählten wir den Event-Driven-Ansatz mit der Umsetzung der Prozesskommunikation mittels Nachrichten. Ignite implementiert bereits zwei Komponenten, die es Knoten ermöglichen, Nachrichten untereinander weiterzuleiten – Communication-SPI und Discovery-SPI.

Ignite Service Grid – Neustart

Communication-SPI ermöglicht es Knoten, direkt zu kommunizieren und Nachrichten weiterzuleiten. Es eignet sich gut zum Versenden großer Datenmengen. Mit Discovery-SPI können Sie eine Nachricht an alle Knoten im Cluster senden. In der Standardimplementierung erfolgt dies über eine Ringtopologie. Es gibt auch eine Integration mit Zookeeper, in diesem Fall wird eine Sterntopologie verwendet. Ein weiterer wichtiger Punkt ist, dass Discovery-SPI garantiert, dass die Nachricht definitiv in der richtigen Reihenfolge an alle Knoten zugestellt wird.

Schauen wir uns das Bereitstellungsprotokoll an. Alle Benutzeranfragen zur Bereitstellung und Aufhebung der Bereitstellung werden über Discovery-SPI gesendet. Dies ergibt Folgendes Garantien:

  • Die Anfrage wird von allen Knoten im Cluster empfangen. Dadurch kann die Anfrage weiter bearbeitet werden, wenn sich der Koordinator ändert. Dies bedeutet auch, dass jeder Knoten in einer Nachricht alle erforderlichen Metadaten enthält, beispielsweise die Dienstkonfiguration und seine serialisierte Instanz.
  • Eine strikte Reihenfolge der Nachrichtenzustellung trägt dazu bei, Konfigurationskonflikte und konkurrierende Anforderungen zu lösen.
  • Da auch der Eintrag des Knotens in die Topologie über Discovery-SPI abgewickelt wird, erhält der neue Knoten alle für die Arbeit mit Diensten notwendigen Daten.

Wenn eine Anfrage empfangen wird, validieren die Knoten im Cluster diese und erstellen Verarbeitungsaufgaben. Diese Aufgaben werden in die Warteschlange gestellt und dann in einem anderen Thread von einem separaten Worker verarbeitet. Die Implementierung erfolgt auf diese Weise, da die Bereitstellung viel Zeit in Anspruch nehmen und den teuren Erkennungsvorgang untragbar verzögern kann.

Alle Anfragen aus der Warteschlange werden vom Deployment Manager verarbeitet. Es verfügt über einen speziellen Worker, der eine Aufgabe aus dieser Warteschlange abruft und sie initialisiert, um mit der Bereitstellung zu beginnen. Danach erfolgen folgende Aktionen:

  1. Jeder Knoten berechnet die Verteilung dank einer neuen deterministischen Zuweisungsfunktion unabhängig.
  2. Knoten generieren eine Nachricht mit den Ergebnissen der Bereitstellung und senden sie an den Koordinator.
  3. Der Koordinator aggregiert alle Nachrichten und generiert das Ergebnis des gesamten Bereitstellungsprozesses, das über Discovery-SPI an alle Knoten im Cluster gesendet wird.
  4. Wenn das Ergebnis empfangen wird, endet der Bereitstellungsprozess, woraufhin die Aufgabe aus der Warteschlange entfernt wird.

Ignite Service Grid – Neustart
Neues ereignisgesteuertes Design: org.apache.ignite.internal.processors.service.IgniteServiceProcessor.java

Tritt während der Bereitstellung ein Fehler auf, nimmt der Knoten diesen Fehler sofort in eine Nachricht auf, die er an den Koordinator sendet. Nach der Nachrichtenaggregation verfügt der Koordinator über Informationen zu allen Fehlern während der Bereitstellung und sendet diese Nachricht über Discovery-SPI. Fehlerinformationen sind auf jedem Knoten im Cluster verfügbar.

Mit diesem Betriebsalgorithmus werden alle wichtigen Ereignisse im Service Grid verarbeitet. Beispielsweise ist eine Änderung der Topologie auch eine Meldung über Discovery-SPI. Und im Allgemeinen erwies sich das Protokoll im Vergleich zu den Vorgängern als recht leichtgewichtig und zuverlässig. Genug, um jede Situation während des Einsatzes zu bewältigen.

Was wird als nächstes passieren?

Nun zu den Plänen. Jede größere Änderung am Ignite-Projekt wird als Ignite-Verbesserungsinitiative, genannt IEP, abgeschlossen. Die Neugestaltung des Service Grid hat auch einen IEP - IEP #17 mit dem spöttischen Titel „Ölwechsel im Versorgungsnetz“. Tatsächlich haben wir aber nicht das Motoröl, sondern den gesamten Motor gewechselt.

Wir haben die Aufgaben im IEP in 2 Phasen unterteilt. Die erste Phase ist eine große Phase, die aus der Überarbeitung des Bereitstellungsprotokolls besteht. Es ist bereits im Master enthalten, Sie können das neue Service Grid ausprobieren, das in Version 2.8 erscheinen wird. Die zweite Phase umfasst viele weitere Aufgaben:

  • Hot-Neubereitstellung
  • Dienstversionierung
  • Erhöhte Fehlertoleranz
  • Dünner Kunde
  • Tools zur Überwachung und Berechnung verschiedener Metriken

Abschließend beraten wir Sie zu Service Grid zum Aufbau fehlertoleranter, hochverfügbarer Systeme. Wir laden Sie auch ein, uns zu besuchen Entwicklerliste и Benutzerliste Teile deine Erfahrung. Ihre Erfahrung ist für die Community wirklich wichtig; sie wird Ihnen helfen zu verstehen, wohin Sie als Nächstes gehen und wie Sie die Komponente in Zukunft weiterentwickeln können.

Source: habr.com

Kommentar hinzufügen