
Wir sind eine Abteilung für die Entwicklung von Einzelhandelstechnologien. Einmal stellte das Management die Aufgabe, die volumetrischen Berechnungen mithilfe von Apache Ignite in Verbindung mit MSSQL zu beschleunigen, und zeigte eine Site mit schönen Abbildungen und Beispielen für Java-Code. Die Site mochte sofort Zero Deployment , dessen Beschreibung Wunder verspricht: Sie müssen Ihren Java- oder Scala-Code nicht manuell auf jedem Knoten im Grid bereitstellen und ihn bei jeder Änderung erneut bereitstellen. Im Laufe der Arbeit stellte sich heraus, dass Zero Deployment eine bestimmte Verwendung hat, deren Funktionen ich teilen möchte. Unter der Katze Reflexionen und Implementierungsdetails.
1. Erklärung des Problems
Das Wesentliche des Problems ist wie folgt. Es gibt ein Verkaufsstellenverzeichnis für SalesPoint und ein Verzeichnis der Produkte Sku (Stock Keeping Unit). Die Verkaufsstelle hat das Attribut "Filialtyp" mit den Werten "klein" und "groß". Ein Sortiment (eine Liste der Waren einer Verkaufsstelle) ist mit jeder Verkaufsstelle verbunden (aus einem DBMS geladen), und es wird angegeben, dass das angegebene Produkt datiert wurde
aus dem Sortiment ausgeschlossen oder dem Sortiment hinzugefügt.
Es ist erforderlich, einen partitionierten Cache mit Verkaufsstellen zu organisieren und einen Monat im Voraus Informationen über verbundene Waren darin zu speichern. Für die Kompatibilität mit dem Kampfsystem muss der Ignite-Clientknoten Daten herunterladen, ein Aggregat des Typs (Geschäftstyp, Produktcode, Tag, Anzahl der Verkaufsstellen) berechnen und wieder in das DBMS hochladen.
2. Das Studium der Literatur
Noch keine Erfahrung, also fange ich an, vom Herd aus zu tanzen. Das heißt, mit einer Überprüfung der Veröffentlichungen.
Ein Artikel aus dem Jahr 2016 zur Einführung in Apache Ignite: Die ersten Schritte enthalten einen Link zur Apache Ignite-Projektdokumentation und werfen ihm gleichzeitig Vorwürfe zum Verwischen vor. Ich habe es ein paar Mal gelesen, Klarheit kommt nicht. Wenden wir uns dem offiziellen Tutorial für den Einstieg zu
verspricht optimistisch "Sie werden im Handumdrehen einsatzbereit sein!". Ich verstehe die Einstellungen von Umgebungsvariablen und schaue mir zwei Apache Ignite Essentials-Videos an. Sie erwiesen sich als nicht sehr nützlich für meine spezielle Aufgabe. Ich starte Ignite erfolgreich über die Befehlszeile mit der Standarddatei "example-ignite.xml". Ich erstelle die erste Compute-Anwendung mit Maven. Die Anwendung funktioniert und verwendet Zero Deployment, was für eine Schönheit!
Ich habe weiter gelesen und dort verwendet das Beispiel sofort affinityKey (zuvor durch eine SQL-Abfrage erstellt), und sogar das mysteriöse BinaryObject wird angewendet:
IgniteCache<BinaryObject, BinaryObject> people = ignite.cache("Person").withKeepBinary();
Ich habe ein wenig gelesen: Das Binärformat ist ein bisschen eine Reflexion, der Zugriff auf die Felder eines Objekts mit Namen. Es kann den Wert eines Feldes lesen, ohne das Objekt vollständig zu deserialisieren (Speicherplatz sparen). Aber warum wird BinaryObject anstelle von Person verwendet, weil es keine Bereitstellung gibt? Warum wird IgniteCache <Schlüssel, Person> in IgniteCache <BinaryObject, BinaryObject> übersetzt? Es ist noch nicht klar.
Ich überarbeite Compute Application für meinen Fall. Der Primärschlüssel des Point-of-Sale-Verzeichnisses in MSSQL ist definiert als [id] [int] NOT NULL. Ich erstelle analog einen Cache
IgniteCache<Integer, SalesPoint> salesPointCache=ignite.cache("spCache")
In der xml-config gebe ich an, dass der Cache partitioniert ist
<bean class="org.apache.ignite.configuration.CacheConfiguration"> <property name="name" value="spCache"/> <property name="cacheMode" value="PARTITIONED"/> </bean>
Bei der Partitionierung nach Verkaufsstellen wird davon ausgegangen, dass das erforderliche Aggregat auf jedem Knoten des Clusters für die dortigen salesPointCache-Datensätze erstellt wird. Anschließend führt der Clientknoten die endgültige Summierung durch.
Ich habe das Tutorial zur ersten Ignite Compute-Anwendung gelesen und mache es analog. Auf jedem Knoten des Clusters führe ich IgniteRunnable () aus, ungefähr so:
@Override public void run() { SalesPoint sp=salesPointCache.get(spId); sp.calculateSalesPointCount(); .. }
Ich füge Aggregations- und Upload-Logik hinzu und führe einen Testdatensatz aus. Vor Ort funktioniert alles auf dem Entwicklungsserver.
Ich starte zwei CentOs-Testserver, gebe IP-Adressen in der Datei default-config.xml an und führe sie jeweils aus
./bin/ignite.sh config/default-config.xml
Beide Ignite-Knoten starten und sehen sich. Ich gebe die erforderlichen Adressen in der XML-Konfiguration der Client-Anwendung an, sie startet, fügt der Topologie einen dritten Knoten hinzu und sofort gibt es wieder zwei Knoten. Das Protokoll lautet "ClassNotFoundException: model.SalesPoint" in der Zeile
SalesPoint sp=salesPointCache.get(spId);
Laut StackOverflow liegt die Fehlerursache darin, dass CentOs-Server keine benutzerdefinierte SalesPoint-Klasse haben. Angekommen. Wie müssen Sie Ihren Java-Code nicht manuell auf jedem Knoten und danach bereitstellen? Oder geht es in Ihrem Java-Code nicht um SalesPoint?
Ich habe wahrscheinlich etwas verpasst - wieder beginne ich zu suchen, zu lesen und wieder zu suchen. Mit der Zeit habe ich das Gefühl, dass ich alles zu diesem Thema gelesen habe, es gibt nichts Neues. Bei der Suche habe ich einige interessante Kommentare gefunden.
Valentin Kulichenko, Leitender Architekt bei GridGain Systems, Antwort auf StackOverflow, April 2016:
Model classes are not peer deployed, but you can use withKeepBinary() flag on the cache and query BinaryObjects. This way you will avoid deserialization on the server side and will not get ClassNotFoundException.
Eine weitere maßgebliche Stellungnahme: Denis Magda , Direktor für Produktmanagement bei GridGain Systems.
Ein Artikel über Microservices über Habré bezieht sich auf drei Artikel von Denis Magda: Microservices Teil I , Microservices Teil II , Microservices Teil III 2016-2017. In einem zweiten Artikel schlägt Denis vor, einen Clusterknoten über MaintenanceServiceNodeStartup.jar zu starten. Sie können den Start auch mit der XML-Konfiguration und der Befehlszeile verwenden. Anschließend müssen Sie jedem bereitgestellten Clusterknoten manuell benutzerdefinierte Klassen hinzufügen:
That's it. Start (..) node using MaintenanceServiceNodeStartup file or pass maintenance-service-node-config.xml to Apache Ignite's ignite.sh/bat scripts. If you prefer the latter then make sure to build a jar file that will contain all the classes from java/app/common and java/services/maintenance directories. The jar has to be added to the classpath of every node where the service might be deployed.
In der Tat, das war's. Hier stellt sich heraus, warum dieses mysteriöse Binärformat!
3. SingleJar
Denis belegte den ersten Platz in meiner persönlichen Bewertung, IMHO das nützlichste Tutorial von allen verfügbaren. Sein Github MicroServicesExample enthält ein vollständig vorgefertigtes Beispiel für die Konfiguration von Clusterknoten, die ohne zusätzliche Kniebeugen kompiliert werden.
Ich mache es in der Abbildung und Ähnlichkeit, ich bekomme eine einzelne JAR-Datei, die den "Datenknoten" oder "Client-Knoten" je nach Befehlszeilenargument ausführt. Die Assembly wird gestartet und ausgeführt. Zero Deployment ist besiegt.
Der Übergang von Megabyte Testdaten zu zehn Gigabyte Kampfdaten zeigte, dass das Binärformat aus gutem Grund existiert. Es war notwendig, den Speicherverbrauch auf Knoten zu optimieren, und hier war BinaryObject sehr nützlich.
4. Schlussfolgerungen
Die erste Rüge, die wir wegen der verschwommenen Dokumentation des Apache Ignite-Projekts erlebten, erwies sich als fair. Sie hat sich seit 2016 ein wenig geändert. Für Anfänger ist es nicht einfach, einen funktionierenden Prototyp basierend auf einer Site und / oder einem Repository zu erstellen.
Als Ergebnis der geleisteten Arbeit schien Zero Deployment zu funktionieren, jedoch nur auf Systemebene. Etwa so: BinaryObject wird verwendet, um Remote-Cluster-Knoten das Arbeiten mit benutzerdefinierten Klassen beizubringen. Zero Deployment - Interner Mechanismus
Apache Ignite selbst und verteilt Systemobjekte im Cluster.
Ich hoffe, meine Erfahrung wird neuen Apache Ignite-Benutzern nützlich sein.