Wie kann eine Regelengine in eine Microservice-Architektur integriert werden, wenn viele Eingabedaten erforderlich sind?

12

Momentane Situation

Wir implementieren (und warten jetzt) ​​eine Online-Shopping-Webanwendung in einer Microservice-Architektur.

Eine der Anforderungen ist, dass das Unternehmen in der Lage sein muss, Regeln für das Hinzufügen unserer Kunden zu ihrem Warenkorb anzuwenden, um ihre Erfahrung und die eventuelle Bestellung anzupassen. Ganz offensichtlich musste eine Business Rules Engine eingerichtet werden, und wir haben dafür einen speziellen "Microservice" implementiert (wenn wir es noch so nennen könnten).

Im Laufe eines Jahres wurde diese Regelengine immer komplexer und erforderte immer mehr Daten (z. B. Inhalt des Warenkorbs, aber auch Benutzerinformationen, seine Rolle, seine vorhandenen Dienste, einige Rechnungsinformationen usw.), um in der Lage zu sein Berechnen Sie diese Regeln.

Im Moment shopping-cartsammelt unser Microservice all diese Daten von anderen Microservices. Obwohl ein Teil dieser Daten von verwendet wird shopping-cart, wird sie meistens hauptsächlich zum Zuführen der Regelengine verwendet.

Neue Anforderungen

Jetzt besteht die Notwendigkeit, dass andere Anwendungen / Mikrodienste die Regelengine für ähnliche Anforderungen wiederverwenden. In der aktuellen Situation müssten sie daher dieselbe Art von Daten übertragen, dieselben Mikrodienste aufrufen und (fast) dieselben Ressourcen aufbauen, um die Regelengine aufrufen zu können.

Wenn wir so weitermachen, werden wir mit mehreren Problemen konfrontiert sein:

  • Jeder (Aufruf der Regelengine) muss das Abrufen der Daten erneut implementieren, auch wenn er sie nicht für sich selbst benötigt.
  • Die Anforderungen an die Regelengine sind komplex.
  • Wenn wir in dieser Richtung fortfahren, müssen wir diese Daten für viele Anforderungen im gesamten Netzwerk transportieren (denken Sie an μs A, das μs B aufruft und die Regelengine aufruft, aber A hat bereits einige der Daten, die die Regelengine benötigt).
  • shopping-cart ist aufgrund all des Datenabrufs riesig geworden;
  • Ich vergesse wahrscheinlich viele ...

Was können wir tun, um diese Probleme zu vermeiden?

Im Idealfall würden wir vermeiden, die Regelengine komplexer zu gestalten. Wir müssen auch sicherstellen, dass es nicht zu einem Engpass kommt - zum Beispiel sind einige Daten ziemlich langsam abzurufen (10s oder sogar mehr), daher haben wir das Vorabrufen so implementiert, shopping-cartdass die Daten mit größerer Wahrscheinlichkeit vorhanden sind, bevor wir die Regeln aufrufen Motor, und halten Sie eine akzeptable Benutzererfahrung.

Einige Ideen

  1. Lassen Sie die Regelengine die benötigten Daten abrufen. Dies würde die Komplexität noch erhöhen und das Prinzip der Einzelverantwortung verletzen ( noch mehr… ).
  2. Implementieren Sie einen Proxy μs vor der Regelengine, um die Daten abzurufen.
  3. Implementieren Sie einen "Datenabruf" μs, den die Regelengine aufruft, um alle benötigten Daten auf einmal abzurufen (zusammengesetzte Abfrage).
Didier L.
quelle
Lassen Sie mich dies zusammenfassen (mit Fragen): Sie haben mehrere Microservices für einen Shop implementiert. Einer von ihnen ist ein Einkaufswagen . In den Warenkorb ist eine Regel-Engine (entweder Homebrew oder ein Produkt) integriert, oder? Wenn ein Benutzer einen Artikel zum Warenkorb hinzufügt, wird die Regel-Engine als Teil der Geschäftslogik aktiviert und ändert den Warenkorb irgendwie (z. B. Rabatt- oder Bundle-Produkte), oder? Jetzt möchte auch ein anderer Microservice Regeln verwenden , die auf ähnlichen Eingabedaten basieren können, oder? Und die Eingabedaten werden von anderen Microservices bereitgestellt, oder? Warum ist das Abrufen der Daten so komplex?
Andy
3
Ihre beste Möglichkeit, diese Probleme zu vermeiden, besteht darin, die Regelengine loszuwerden.
Whatsisname
@Andy Die Regelengine ist ein separater Microservice. Die API ist ein bisschen zugeschnitten shopping-cart, aber wir könnten sie ganz einfach an die Bedürfnisse der anderen Microservices anpassen (sie beziehen sich immer noch auf Benutzer, Produkte und Bestellungen). Aus unserer Sicht benötigen sie dieselben Eingabedaten, insbesondere da das Unternehmen die anzuwendenden Prädikate auswählen kann. Alle Daten werden von anderen Microservices mit Ausnahme des Warenkorbinhalts selbst bereitgestellt. Die Daten - Abruf ist nicht komplex per se , aber es wird komplizierter , wenn Sie ~ 10 andere Microservices verlangen und mit dem durch die Regel - Engine erwartet aufrechtzuerhalten.
Didier L
@whatsisname Ich bin auch kein großer Fan von einer Regel-Engine im Allgemeinen, aber zum gegenwärtigen Zeitpunkt müssen wir uns damit befassen und sowieso, und das Unternehmen ändert seine Konfiguration täglich. Selbst wenn wir es loswerden würden, würden wir immer noch eine konfigurierbare Komponente benötigen, um die gleichen Dinge zu tun, die die gleichen Eingabedaten erfordern ... Es wäre immer noch eine Regelengine, nur mit einem anderen Namen, und wir würden immer noch die gleichen Probleme haben.
Didier L

Antworten:

8

Lassen Sie uns für eine Sekunde einen Schritt zurücktreten und unseren Startplatz bewerten, bevor wir diese Antwort schreiben, die wahrscheinlich neuartig ist. Du hast:

  • Ein großer Monolith (die Regelmaschine)
  • Eine große Menge nicht modularisierter Daten, die in großen Mengen gesendet werden
  • Es ist schwierig, Daten zur und von der Regelengine zu erhalten
  • Sie können die Regelengine nicht entfernen

Ok, das ist nicht so toll für Microservices. Ein sofortiges Problem ist, dass ihr anscheinend falsch versteht, was Microservices sind.

Jeder (Aufruf der Regelengine) muss das Abrufen der Daten erneut implementieren, auch wenn er sie nicht für sich selbst benötigt.

Sie müssen eine Art API oder Kommunikationsmethode definieren, die Ihre Microservices verwenden, und diese gemeinsam verwenden. Dies kann eine Bibliothek sein, die alle importieren können. Möglicherweise wird ein Nachrichtenprotokoll definiert. Möglicherweise wird ein vorhandenes Tool verwendet ( suchen Sie nach Microservice-Nachrichtenbussen als guten Ausgangspunkt).

Die Frage der dienstübergreifenden Kommunikation ist an sich kein "gelöstes" Problem, aber es ist an dieser Stelle auch kein "Roll your own" -Problem. Viele vorhandene Werkzeuge und Strategien können Ihnen das Leben erheblich erleichtern.

Wählen Sie unabhängig davon, was Sie tun, ein einzelnes System aus und versuchen Sie, Ihre Kommunikations-APIs anzupassen, um dies zu verwenden. Ohne eine definierte Art der Interaktion Ihrer Dienste haben Sie alle Nachteile von Mikrodiensten und monolithischen Diensten und keinen der Vorteile von beiden.

Die meisten Ihrer Probleme ergeben sich daraus.

Die Anforderungen an die Regelengine sind komplex.

Machen Sie sie weniger komplex.

Finden Sie Wege, um sie weniger komplex zu machen. Ernsthaft. Gängige Datenmodelle, teilen Sie Ihre Single Rules Engine in kleinere auf oder so. Sorgen Sie dafür, dass Ihre Regelengine besser funktioniert. Nehmen Sie nicht den Ansatz "Alles in die Abfrage einbinden und sie immer wieder komplizieren" - schauen Sie sich ernsthaft an, was Sie tun und warum.

Definieren Sie ein Protokoll für Ihre Daten. Ich vermute, Sie haben keinen definierten API-Plan (wie oben beschrieben) und haben begonnen, REST-Aufrufe bei Bedarf ad hoc zu schreiben. Dies wird immer komplexer, da Sie jetzt jedes Mal, wenn etwas aktualisiert wird, jeden Microservice warten müssen.

Besser noch, Sie sind nicht gerade das erste Unternehmen, das jemals ein Online-Shopping-Tool implementiert hat. Erforschen Sie andere Unternehmen.

Was jetzt...

Danach haben Sie zumindest einige der größten Probleme ausprobiert.

Das nächste Problem ist diese Frage Ihrer Regelengine. Ich hoffe, dass dies einigermaßen staatenlos ist, so dass Sie es skalieren können. Wenn dies der Fall ist, werden Sie, obwohl Sie nicht optimal sind, zumindest nicht in einem Glanz der Herrlichkeit sterben oder verrückte Problemumgehungen entwickeln.

Sie möchten, dass Ihre Regelengine zustandslos ist. Stellen Sie sicher, dass nur Daten verarbeitet werden. Wenn Sie es als Engpass empfinden, machen Sie es so, dass Sie mehrere hinter einem Proxy / Load Balancer ausführen können. Nicht ideal, aber immer noch praktikabel.

Überlegen Sie sich einige Zeit, ob Ihre Microservices wirklich in Ihre Regelengine aufgenommen werden sollten. Wenn Sie den Systemaufwand so erheblich erhöhen, um eine "Microservices-Architektur" zu erreichen, müssen Sie mehr Zeit für die Planung aufwenden.

Kann Ihre Regel-Engine alternativ in Teile geteilt werden? Sie können Gewinne erzielen, indem Sie nur Teile Ihrer Regelengine für bestimmte Dienste erstellen.

Wir müssen auch sicherstellen, dass es nicht zu einem Engpass wird - zum Beispiel sind einige Daten ziemlich langsam abzurufen (10s oder sogar mehr).

Angenommen, dieses Problem besteht, nachdem Sie die oben genannten Probleme gelöst haben, müssen Sie ernsthaft untersuchen, warum dies geschieht. Sie haben einen Albtraum, aber anstatt herauszufinden, warum (10 Sekunden? Zum Versenden von Einkaufsportaldaten ? Rufen Sie mich zynisch an, aber das scheint ein bisschen absurd), scheinen Sie die Symptome zu korrigieren, anstatt das Problem zu betrachten, das die Symptome verursacht den ersten Platz.

Sie haben den Ausdruck "Datenabruf" immer und immer wieder verwendet. Befinden sich diese Daten in einer Datenbank? Wenn nicht, sollten Sie dies in Betracht ziehen. Wenn Sie so viel Zeit damit verbringen, Daten "manuell" abzurufen, scheint es eine gute Idee zu sein, eine echte Datenbank zu verwenden.

Möglicherweise können Sie ein Design mit einer Datenbank für die Daten, die Sie abrufen (je nachdem, was dies ist, haben Sie es oft erwähnt), einige Regel-Engines und Ihre Clients haben.

Ein letzter Hinweis ist, dass Sie sicherstellen möchten, dass Sie die richtige Versionierung Ihrer APIs und Dienste verwenden. Eine kleinere Version sollte die Abwärtskompatibilität nicht beeinträchtigen. Wenn Sie feststellen, dass alle Ihre Dienste gleichzeitig freigegeben werden, damit sie funktionieren, verfügen Sie nicht über eine Microservice-Architektur, sondern über eine verteilte monolithische Architektur.

Und letztendlich sind Microservices keine Einheitslösung. Bitte, um all dem willen, was heilig ist, tu es nicht einfach, weil es die neue Hüftsache ist.

Enderland
quelle
Vielen Dank für Ihre Antwort, @enderland. In der Tat ist die Microservice-Architektur für uns noch relativ neu, daher diese Frage. Diese Regel-Engine hat sich ein bisschen organisch weiterentwickelt, um uns hierher zu führen. Deshalb brauchen wir jetzt eine Wegbeschreibung, um sie zu beheben. Es ist (zum Glück) völlig zustandslos, daher die Datenmenge, die als Eingabe verwendet wird. Und das möchten wir zuerst angehen, um es zu einer wiederverwendbaren Komponente zu machen. Aber wie kann man die Menge der Eingabedaten reduzieren, ohne die Anzahl der verfügbaren Prädikate zu verringern? Ich denke, wir brauchen eine API, die in der Lage ist, die Daten selbst abzurufen, aber wie kann man sie richtig architektonisch gestalten?
Didier L
Leistungsprobleme stammen von Microservices, die langsame JMS- und SOAP-Dienste aufrufen, die von Back-Ends implementiert werden. Sie haben ihre eigenen Datenbanken, aber die Leistung ist nicht wirklich ihr erstes Ziel (solange sie die Last bewältigt). Und es gibt zu viele von ihnen, um in Betracht zu ziehen, ihre Daten zu replizieren und zu pflegen (für einige tun wir dies jedoch). Das Beste, was wir tun können, ist das Zwischenspeichern und Vorabrufen.
Didier L
Wenn Sie also " wenige Regel-Engines " erwähnen , meinen Sie damit spezialisierte Regel-Engines, die nur Prädikate mit einem Eingabetyp auswerten, oder? Würden Sie vorschlagen, dass sie die benötigten Daten abrufen, oder sollten sie im Voraus abgerufen werden? Wir würden dann auch eine Komponente benötigen, um die Kombination von Prädikaten zu orchestrieren, oder? Achten Sie darauf, dass Sie aufgrund dieser Orchestrierung nicht zu viel Netzwerk-Overhead hinzufügen.
Didier L
1

Angesichts der Menge an Informationen, die über die Regelengine und ihre Ein- und Ausgaben präsentiert werden, denke ich, dass Ihr Vorschlag Nr. 2 ist auf dem richtigen Weg.

Die derzeitigen Verbraucher der Regelengine könnten den Prozess des Sammelns der erforderlichen Informationen an eine speziellere Komponente auslagern.

Beispiel: Sie verwenden derzeit die Regelengine, um Rabatte zu berechnen, die auf den Inhalt des Warenkorbs angewendet werden müssen. Frühere Einkäufe, Geografie und aktuelle Angebote spielen dabei eine Rolle.

Die neue Anforderung besteht darin, einen Großteil dieser Informationen zu verwenden, um Angebote an frühere Kunden zu senden, die auf bevorstehenden Sonderangeboten und früheren Einkäufen basieren. Frühere Einkäufe, aktuelle und bevorstehende Angebote spielen dabei eine Rolle.

Ich hätte zwei separate Dienste dafür. Sie würden sich bei einigen ihrer schweren Arbeiten auf die Regeln des Motorservices verlassen. Jeder von ihnen würde die erforderlichen Daten für seine Anfrage an die Regelengine sammeln.

Die Regelengine wendet nur die Regeln an, die Verbraucher müssen sich keine Gedanken darüber machen, welche genauen Daten die Regelengine für den jeweiligen Kontext benötigt, und diese neuen Vermittlungsdienste tun nur eines: Zusammenstellen des Kontexts und Weiterleiten der Anforderung an die Regelengine und gibt die Antwort unverändert zurück.

Soren L. Hansen
quelle
0

Das Aggregieren der für die Entscheidung erforderlichen Daten sollte außerhalb der Regelengine erfolgen. Dies liegt daran, dass sie am besten als zustandslose Dienste wie möglich konzipiert sind. Das Abrufen von Daten umfasst notwendigerweise eine asynchrone Verarbeitung und das Halten des Status. Es spielt keine Rolle, ob das Abrufen von einem Proxy erfolgt, der dem Entscheidungsdienst gegenübersteht, von den Anrufern oder von einem Geschäftsprozess.

Als praktische Angelegenheit für die Implementierung möchte ich erwähnen, dass IBM Operational Decision Manager mit der Dokumentation beginnt und bereits die Verwendung des Produkts in Docker-Containern unterstützt . Ich bin sicher, dass auch andere Produkte diese Unterstützung bieten und dass sie zum Mainstream werden.

David Williams
quelle
0

In meinem einfachen Denken, denke ich, wird es hilfreich sein, alle erforderlichen Daten vorab abzurufen, indem eine Reihe von asynchronen Aufrufen an Datenabrufdienste getätigt wird, sobald der Kunde mit dem Kauf beginnt und die Daten zwischenspeichert. Wenn Sie also den Regeldienst aufrufen müssen, sind die Daten bereits vorhanden. Und weiterhin während der Sitzung für andere Dienste verfügbar sein.

Ashok
quelle