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-cart
sammelt 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-cart
dass die Daten mit größerer Wahrscheinlichkeit vorhanden sind, bevor wir die Regeln aufrufen Motor, und halten Sie eine akzeptable Benutzererfahrung.
Einige Ideen
- 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… ).
- Implementieren Sie einen Proxy μs vor der Regelengine, um die Daten abzurufen.
- Implementieren Sie einen "Datenabruf" μs, den die Regelengine aufruft, um alle benötigten Daten auf einmal abzurufen (zusammengesetzte Abfrage).
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.Antworten:
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:
Ok, das ist nicht so toll für Microservices. Ein sofortiges Problem ist, dass ihr anscheinend falsch versteht, was Microservices sind.
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.
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.
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.
quelle
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.
quelle
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.
quelle
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.
quelle