Microservices StrukturPlanung

OnDemand

Top Contributor
Hallo ihr lieben, ich überlege grad wie ich meinen Monolith in Microservices aufteilt. Ich möchte gern mal eure Meinung hören und liebend gern Verbesserungsvorschläge. Geht nur um deinen reinen Plan wie die Services aufgebaut werden.

Beispiel : ich bin Entwickler für eine Werkstatt-Ersatzteil-Software und möchte meine Software an Distributionen verkaufen. Dafür möchte ich pro Kunde eine eigene Datenbank (tenant)

Das Programm im groben folgendes:

1. Abholung von Fahrzeug-Ersatzteil-Daten (Preis, Lagerbestand usw) von 50 verschiedenen Herstellern
- CSV, API oder TXT jeder Anbieter hat eine komplett andere Schnittstelle​

2. Daten werden gelesen und aufbereitet
-Namen ergänzt, VK Preise berechnet​

3. Die Daten werden in die Datenbank für den Kunden gespeichert

4. Die Daten werden an Werkstätten überspielt / Eine API steht bereit um die DAten durch eine Werkstatt abfragen zu lassen

Das Ganze passiert stündlich, bestehende Teile werden nur updated (Preis, Bestand)


Nun hab ich einen Prototyp wie folgt, bin aber nicht so richtig zufrieden da es viele Abhängigkeiten gibt.

1. Zuul als Api Gateway
2. Eureka Nameserver
3. Master-Service
4. Hersteller XY Service
5. Hersteller AB Service
6. Hersteller ZZ Service
7. Pojo Projekt
ff.

Jeder Herstellerservice holt die Daten ab, bereitet sie auf und schickt sie an den Masterservice. Der Masterservice bekommt im Header den tenant mitgeteilt, und speichert es in die entsprechende DB des Kunden. Funktioniert auch alles

Das PojoProjekt hat alle @Entity und DTOs modelliert, jeder Hersteller hat dazu eine Abhängigkeit damit ich das Objekt "Ersatzteil" nur in einem Projekt pflegen muss, und nicht in jedem Service. Ist blöd ich weiß, aber jeder Herstellerservice muss wissen was an den Master schicken muss.

Das Ganze klappt auch wie ich es will, ist aber nicht so gut wartbar und die Abhängigkeiten sind mir zu groß, vor allem aber gefällt mir nicht, dass der Masterservice "das Herzstück" ist. Wenn der Down ist, geht nix mehr > alles andere als Microservice-Vorteil

Im Prinzip sollte ja jeder Service eine eigene DB haben, aber aufgrund der Tenant-Anforderung sehe ich das nicht als sinnvoll an. Ich brauch alle Ersatzteildaten eines Kunden in einer DB. Wenn ich nun irgendwann 50 Hersteller habe, hab ich zwar den Vorteil: 1 Hersteller down, die anderen funktionieren noch. Aber der Wartungsaufwand ist schon enorm.

Daher eine weitere Überlegung:
Ich mache einen einzigen Service, der alle Hersteller kennt. Diesen Service kann ich auf den Servern 50 x deployen, aber jede Instanz ist nur für 1 Hersteller zuständig (als Startparam übergeben welchen er macht o.ä.). So hätte ich nur 1 Service zu warten, wenn ich den aber update muss ich alle neustarten.


Ich hoffe jemand erkennt den Knoten den ich hab und kann mir ein wenig helfen.
 

LimDul

Top Contributor
Warum kann nicht jeder Service selber mit dem korrekten Tenant in eine gemeinsame DB schreiben? Warum das über den Master-Service delegiert werden. In der Regel läuft die Datenbank ja eh auf einer eigene Instanz mit entsprechend "WUMMS" dahinter und ist dafür ausgelegt, dass das X User gleichzeitig reinschreibem.
 

OnDemand

Top Contributor
Hi LimDul, stimmt, jeder Service kann ja das Tenant-Gedöns auch haben und jeder Service einen eigenen Pool auf die DB.

Was aber wenn 10 Services parallel neue Teile speichern, kommt die DB damit klar (nicht dass ID doppelt vergeben werden oder sonst was)

Ich nutzer HikariPool, je Tenant hat 2 Connections ,b ei 100 TenantUsern und jeder nutzt vielleicht durchschnittlich 20 Hersteller, macht dass einiges an Connections. Die Datenbank ist ein guter Server mit knapp 25GB Ram, SSD & Co der hat gut wumms und kann bei Bedarf erweitert werden. Da mach ich mir keine Sorgen.

Der Master macht noch weiteres, hab ich ganz vergessen. Zb Kann jeder Benutzer Einstellungen auf Ersatzteil-Artikel-Ebene treffen zb:
- Soll der Artikel deaktiviert werden wenn Bestand < XX
- Preise gewählter Artikel nicht berechnen
- User möchte nicht, dass die Beschreibungen updated/überschrieben werden, weil er es selber macht
usw

Diese "Prüfungen" macht der Master, ist auch nicht richtig.

Im Prinzip müsste jedes Ersatzteil durch eine Art "Filter" welcher das Ersatzteil entsprechend den User-Settings nach dem Lesen manipuliert, bevor es dann in die DB geht. Dieser "Filter" ist für alle Hersteller gleich, und wird immer wieder erweitert. Dafür war der Master mal gedacht, damit nicht in jedem Hersteller Service alles doppelt drin ist (Stichwort Code-Wiederverwendung) aber iwie trifft das bei Microservices nicht zu oder? Ich finde Code Wiederverndung und Unabhängigkeit beißen sich
 

LimDul

Top Contributor
Hi LimDul, stimmt, jeder Service kann ja das Tenant-Gedöns auch haben und jeder Service einen eigenen Pool auf die DB.

Was aber wenn 10 Services parallel neue Teile speichern, kommt die DB damit klar (nicht dass ID doppelt vergeben werden oder sonst was)
Dann nutzt du die DB "falsch".
Datenbanken ist dafür ausgelegt das zu können. Die ID Vergabe muss halt entweder außerhalb der DB so sein, dass Kollisionen ausgeschlossen sind (UUID) oder die IDs werden über Sequencen aus der DB vergeben - dann sind Kollisionen auch ausgeschlossen.
 
K

kneitzel

Gast
Dieser Master-Service irritiert mich auch ein bisschen. Ich kenne es eigentlich so, dass jeder Service seine Daten in einer eigenen Datenbank hält. Also auch nicht einmal eine gemeinsame Datenbank.

Siehe dazu evtl. auch https://microservices.io/patterns/data/database-per-service.html

Und jeder Service ist für einen klaren Bereich zuständig und da mischt sich auch niemand sonst mit rein. Wenn da ein anderer Service etwas braucht, dann spricht er den entsprechend verantwortlichen Service an.

Oder war das Problem jetzt, dass Du mehrere Instanzen eines Services hast? Da musst du dann halt, wie von LimDul vorgeschlagen vorgehen.
 

thecain

Top Contributor
Meiner Meinung nach ist der Schnitt der Services schon falsch.

Ich würde Microservices nicht nach Hersteller, sondern nach "Anwendungszweck" trennen. Beispiel für eigene Services:
- Ersatzteile erfassen/ändern/abrufen
- Aufträge erfassen/ändern/abrufen
- Kunden verwalten

Diese Microservices, haben wenn ganz sauber getrennt auch je eigene Datenbanken. Wenn du also nicht eine rechtliche Anforderung hast, nach Hersteller die Datenbanken zu trennen (kann ich mir bei Ersatzteilen nicht vorstellen) macht das auch keinen grossen Sinn.

Wobei ich auch sagen muss, ein Microservice Ansatz ist EINE Lösung. Nur weil das im moment viel gemacht wird, ist es nicht die einzig wahre Lösung.
 

httpdigest

Top Contributor
Meiner Meinung nach ist der Haupttreiber für Microservices - oder einfach nur dafür, mehrere Services zu haben - organisatorischer Natur. Wenn ich mehrere Teams in meinem Unternehmen habe, dann habe ich zwangsläufig auch mehrere Services. Also ganz klassisch Conways Gesetz.
Wenn das nicht gegeben ist, muss man schon nach wirklich guten Gründen für mehrere Services suchen, da man sich bei Aufteilung in mehrere Services alle Probleme und höhere Komplexität eines verteilten Systems hereinholt. Es gibt natürlich gute Gründe für Microservices, aber wie @thecain schon sagt, ist die Verwendung von Microservices eine Lösung. Ein guter, horizontal skalierbarer Monolith wäre auch eine gute Lösung.
 

OnDemand

Top Contributor
Wir hatten das System bereits als Monolith aber wenn der Service abgestürzt ist> Alle Herstellerimporte betroffen, Frontend konnte keine Daten mehr anzeigen usw.

Durch das Aufteilen in mehrere Services die über REST kommunizieren, konnten wir das Problem weitestgehend aus der Welt schaffen.

Wenn der Server down ging, war ein Service binnen 10 Minuten auf einen anderen gezogen und wieder online. Ich sehe in den Microservices wesentlich mehr Flexibilität als wir es mit dem Monolithen hatten. Bringt natürlich Verwaltungsaufwand mit sich, den ich aber auch weiter geben kann wenn es nur um das installieren/umziehen einens Services geht.

Aktuell ist der Importablauf so, was meine Ansicht nach bei einem Monolithen viiiiel Resource braucht. Angenommen 50 User werden mit Daten versogt:

1. Der Hersteller Service holt aus der DB "welche User haben HerstellerAB freigeschaltet und bekommen jetzt den Import", als Antwort bekommt er 50
3. Der Hersteller-Service ruft je im eigenen Thread pro User die CSV Daten ab oder API oder was auch immer, macht 50 Threads die je 10-100MB Daten holen. (Jeder User kann andere Daten haben, einmal Daten für alle ziehen is nich)
3. Die gelesenen Daten werden verarbeitet und an den Master gegeben, der dann die Daten in die DB geschrieben hat

Schritt 1-3 wird jetzt für ALLE 50 Hersteller gemacht im schlimmsten Fall alle zur gleichen Zeit. Heißt also 50 Hersteller x 50 User macht 500 Threads mit jeweils 50MB CSV Daten lesen.

Nutze ich kleine Services, kann ich flexibler reagieren. Wenn nun HersterllerXY 100 statt nur 50 User abarbeiten muss, kann ich den auf einen stärkeren Server packen, wobei ein HerstellerBLA mit nur 2 Usern auf einer kleinen VM für 1 EUR dümpeln könnte.

@thecain die ID wird bereits von der DB vergeben, dann ist das ja schon mal iO
 

LimDul

Top Contributor
Mal als Idee, wenn man beim Master bleiben will. Warum nicht Master & Einzel-Services entkoppeln. Anstelle das die Clients direkt mit dem Master reden pumpen die ihre Daten in eine MessageQueue rein (Kafka und was es da sonst noch so gibt).

Dann hast du den Vorteil:
* Master down => Clients können dennoch weiter nach Kafka Daten pumpen.
* Alle Clients pumpen zufällig gleichzeitig massive Datenmengen rein => Der Master braucht halt länger zum abarbeiten, aber die Clients merken nix davon.
 

mrBrown

Super-Moderator
Mitarbeiter
Klang in einem anderem Thread glaub ich schon mal durch, aber für Unabhängigkeit zwischen den Services könnte man auf ein eher Event-Getriebenes Modell setzen. Kommt natürlich auf die genauen Anforderungen an, in wie weit das umsetzbar ist, zB in wie weit das Abholen der Daten beim Hersteller von irgendwelchen Einstellungen betroffen ist.

Grob etwa:
Ein "Master-Service", der Zugriff auf die DB hat. Dieser enthält die gesamte Business-Logik sowie die API (könnte man trenne, je nach Anforderung).
Ein "Hersteller-Service", der die Daten bei den Herstellen abholt (entweder einer für alle, jeder einen einzelnen, oder irgendeine andere Variante). Der macht nichts anderes, als Daten von den Herstellern regelmäßig pollen und in dein Format bringen (ohne Preis-Berechnung, Kundeneinstellungen berücksichtigen, etc).

Der "Hersteller-Service" veröffentlicht die Daten dann über eine Message-Queue.
Der "Master-Service" holt sie aus der Queue ab, konvertiert die Daten nach Nutzer-Bedingungen etc. pp. und schreibt sie in die Datenbank.


Die einzelnen Komponenten sind unabhängig, man braucht nur ein gemeinsames Format für die Events. Jede Komponente darin kann man beliebig replizieren, Ausfallwahrscheinlichkeit sollte damit sinken. Fällt zB ein Hersteller-Service aus, interessiert das alle anderen nicht. Fällt der Master-Service aus, interessiert das die Hersteller-Services nicht, und dem ganzen kann man durch X parallele Master-Services entgegenarbeiten.

Wenn man es bidirektional braucht (also Master gibt vor, welche Daten die Hersteller-Services holen), dann kann der das ebenso über die MQ veröffentlichen.
 

OnDemand

Top Contributor
@mrBrown das klingt gut. Dann liegen wir nicht soooo weit weg von dem was wir haben. Wir haben jüngst besprochen, dass wir die Importer dumm machen könnten und die wirklich nur die Daten holen und speichern.

Nur müsste die Logik irgendwie informiert werden wenn: Bestand geändert, ekpreis geändert usw. außerdem müsste er über neue artikel informiert werden. Aber die "logik" kann ja gar nicht wissen OB sich was geändert hat, ohne die bestehenden Daten zu lesen.

bisher hat der jedes Produkt genommen, das bestehende geholt und abgeglichen. Das ist natürlich großer Mist, aber es hat geklappt. Bei der Menge an Daten nun ist das nicht mehr praktikabel.

Messaging ist das hier nehm ich an? https://spring.io/guides/gs/messaging-jms/
Das steht mir noch in einem Kurs bevor.
 
Zuletzt bearbeitet:

mrBrown

Super-Moderator
Mitarbeiter
@mrBrown das klingt gut. Dann liegen wir nicht soooo weit weg von dem was wir haben. Wir haben jüngst besprochen, dass wir die Importer dumm machen könnten und die wirklich nur die Daten holen und speichern.
Auf der Ebene Rest vs MessageQueue ist es schon relativ weit weg, es bleibt halt nur bei verschiedenen Services für verschiedene Dinge, die gesamte Kommunikation dazwischen ändert sich allerdings.

Nur müsste die Logik irgendwie informiert werden wenn: Bestand geändert, ekpreis geändert usw. außerdem müsste er über neue artikel informiert werden. Aber die "logik" kann ja gar nicht wissen OB sich was geändert hat, ohne die bestehenden Daten zu lesen.

bisher hat der jedes Produkt genommen, das bestehende geholt und abgeglichen. Das ist natürlich großer Mist, aber es hat geklappt. Bei der Menge an Daten nun ist das nicht mehr praktikabel.
Die Frage ist dabei immer, in wie weit man das überhaupt braucht.

Beispiel Preis:
Deine Variante ist, jede Stunde zu fragen, ob der Preis immer noch 10€ beträgt, und dann den neuen Preis gesagt zu bekommen.
Die andere Variante wäre, das du jede Stunde einfach gesagt bekommst, wie der aktuelle Preis ist.

Statt:
A: Ist der Preis noch 10€?
B: Ja.
A: Ist der Preis noch 10€?
B: Ja.
A: Ist der Preis noch 10€?
B: Nein, 15€.
A: Ist der Preis noch 15€?
B: Ja.

Ist es dann ein:
B: Der Preis ist 10€
B: Der Preis ist 10€
B: Der Preis ist 15€
B: Der Preis ist 15€


Wenn das nicht praktikabel ist, können die "Hersteller-Services" die Daten auch selber speichern, und dann nur Änderungen publishen. Erfordert dann natürlich Datenbanken pro Service, wobei die relativ klein dimensioniert sein können, dort entsteht ja nur sehr kontrollierbare Last.

Hängt aber auch z.B. davon ab, wie aktuell die Daten sein müssen. Aktuell können sie eine Stunde lang falsch sein (wenn ich das oben richtig verstanden hab, abgefragt z.B. um 12:00, Änderung um 12:01, dein Service fragt aber erst um 13:00 wieder nach). Ist das ein hartes Limit oder ein weiches Limit? Wie tragisch ist es, wenn der Client die Daten nicht nur eine Stunde, sondern 2, 3, 4 Stunden lang falsch angezeigt bekommt, oder sogar über mehrere Tage? Damit, dass die Daten nicht aktuell sind, muss das System ja sowieso klar kommen.



Das ist eine mögliche Umsetzung, die praktikabel sein kann. Interessant könnte auch etwas in Richtung reaktive Streams sein.
 

OnDemand

Top Contributor
Sollte schon jede Stunde glücken, 2,3 h ist noch verkraftbar.

Wenn ich die Daten aus dem Hersteller Service ohne Prüfung auf Änderung speichere, wann soll ich in deinem Beispiel den Preis berechnen? Wir haben schon einen Trigger in MSQL gesetzt, der eine Spalte als "preis wurde geändert" auf true setzt wenn er sich ändert. Ein anderer Service hat dann die Preise neu berechnet wo true hatte.

Funktionabel, aber nicht komfortabel.

Das reine Importieren ist iwie nicht das Problem, sondern die ganze Datenaufbereitung. Vielleicht ist es das schlauste wirklich jedem Hersteller Service ein Pojo vorzulegen, "so muss es an den Master gehen" der Master empfängt die Liste an Ersatzteilen und verarbeitet diese, berechnet den Preis usw. und speichert am Ende ab.

Irgendwie nicht so einfach
 

mrBrown

Super-Moderator
Mitarbeiter
Sollte schon jede Stunde glücken, 2,3 h ist noch verkraftbar.
Mal ganz plump gefragt:
* wie wirkt es sich aus, wenn der angezeigte Preis seit 50min nicht mehr stimmt?
* wie wirkt es sich aus, wenn der Preis seit drei Tage nicht mehr stimmt?

Irgendwie muss ja sowieso schon mit dem nicht stimmenden Preis umgegangen werden?

Wirklich relevant wird das aber nur dafür, wie Ausfallsicher das sein muss. Ist es verkraftbar, wenn (im Fehlerfall!) mal 3 Stunden keine Änderung erkannt wird? Ist es schlimm, wenn einzelne Änderungen im Nirvana verloren gehen? Reicht es vielleicht auch, dass zwar im Normalfall stündlich Änderungen kommen, aber verlorenen Änderungen nicht schlimm sind, weil Sonntag um Mitternacht immer ein voller Abgleich durchgeführt wird?
(Keine Fragen an dich, nur Gedanken die man sich machen sollte.)


Wenn ich die Daten aus dem Hersteller Service ohne Prüfung auf Änderung speichere, wann soll ich in deinem Beispiel den Preis berechnen? Wir haben schon einen Trigger in MSQL gesetzt, der eine Spalte als "preis wurde geändert" auf true setzt wenn er sich ändert. Ein anderer Service hat dann die Preise neu berechnet wo true hatte.
Das klingt schon sehr fragil...

Die Prüfung auf Änderung kann ja trotzdem statt finden, die muss nicht übersprungen werden.

In der einfachsten Variante pullt der Hersteller-Service Daten vom Hersteller und veröffentlicht dann einfach ein Event "Artikel X: 10€"
Master-Service bekommt das Event, und kann damit jetzt machen was er will. Direkt in die DB schreiben und ein Flag setzen, oder direkt den neuen Preis berechnen und nur das fertige Resultat in die DB schreiben.
Oder sogar einen weiteren Service dazwischen schalten, der empfängt das "Artikel X: 10€", berechnet den neuen Preis, veröffentlicht das dann wieder als Event, und erst das bekommt der Master-Service, der es in die DB schreibt.

Denkbar sind die viele Varianten.

(Das ganze ist übrigens auch innerhalb eines Monolithen genauso umsetzbar, Fehler beeinträchtigen dann natürlich das Gesamtsystem und nicht einzelne Services, aber als Zwischenschritt kann das durchaus praktikabel sein.)

Vielleicht ist es das schlauste wirklich jedem Hersteller Service ein Pojo vorzulegen, "so muss es an den Master gehen"
Die Services nur Daten veröffentlichen lassen, die die anderen Services auch verstehen, ist so oder so meist sinnvoll, sonst kann ja niemand was damit anfangen :)


Irgendwie nicht so einfach
Du musst dir halt bewusst machen, an welchen Punkten man sinnvoll schneiden kann, welche Grenzen es innerhalb des Systems gibt, welche "Bounded Contexts"es gibt, was für Anforderungen du in Bezug auf Skalierbarkeit, Ausfallsicherheit etc hast.

Wenn man due Grundlegenden Fragen beantwortet hat, man sinnvolle Modelle etc hat, kann man damit relativ gut weiterarbeiten.
Wenn man allerdings weder Domäne noch Anforderungen klar genug kennt, ist es wirklich schwierig :)
 

mrBrown

Super-Moderator
Mitarbeiter
Generell noch als Anmerkung: Aus dem Monolithen einen "verteilten Monolithen" machen, bei dem alle Services über Rest kommunizieren, ist meistens nicht der beste Weg und kann potentiell sogar zu mehr Problemen führen. Bevor das einfach überstürzt gemacht wird, sollte man sich das gut überlegen - und in jedem Fall ist eine Modularisierung innerhalb des Monolithen sinnvoll und schon fast Voraussetzung.
 

Dukel

Top Contributor
Wieso lässt man das pushen nicht weg und die Ziele greifen auf die gemeinsame DB zu. Dann gäbe es keinen Zeitversatz und alle hätten einen Stand.
 

mrBrown

Super-Moderator
Mitarbeiter
Wieso lässt man das pushen nicht weg und die Ziele greifen auf die gemeinsame DB zu. Dann gäbe es keinen Zeitversatz und alle hätten einen Stand.
Den Zeitversatz gibt es durch das stündliche Pollen, das hat man in jedem Fall.

Eine gemeinsame DB kann Vorteile haben, kann aber eben auch Probleme mit sich bringen, zT wurden ja schon welche genannt. Die Services müssen alle das passende DB-Format kennen, die Daten-Verarbeitung muss man entweder in jedem Service duplizieren (zb das Preis berechnen), oder man muss das in der DB mit Flags hinterlegen und regelmäßig pollen, Probleme mit der DB betreffen dann alle Systeme, ...
 

Dukel

Top Contributor
Wenn ich den Workflow richtig verstanden habe gibt es einen Import von unterschiedlichen Quellen in eine DB. Daten aus der DB werden regelmäßig an die Kunden gepusht (oder die Kunden pullen) in derren tenant DB.
Wenn man die tenant DB weg lässt und die Kunden greifen auf die Zentrale DB zu hat man keinen Zeitversatz. U.u. kann im hintergrund regemäßig in die tenant DB gecacht werden, wenn die Verbindung wegfallen sollte.
 

temi

Top Contributor
Ich will mich nicht groß einmischen, aber nur zum Verständnis:

Hersteller ist nicht gleich Kunde, oder?

Kann man sich das grob so vorstellen, dass es sich um eine Ersatzteil-DB handelt, die Ersatzteile von verschiedenen Herstellern für verschiedene Kunden verwaltet? Die Preise kommen von den Herstellern und werden von den Kunden aus deiner DB abgerufen? Stellen die Hersteller eine API zum Abruf zur Verfügung oder sitzt da einer vorm Computer und tippt Preislisten? Was legt fest, welcher Kunde auf welche Ersatzteile zugreifen kann? Kann ein Ersatzteil dann auch mehreren Kunden zugeordnet sein?

Edit: Ganz naiv klingt das nach einer DB für die Teile und für jeden Hersteller ein Service, der die aktuellen Daten, wie auch immer, abruft und in der DB aktualisiert. Dazu noch ein Service, der die API für die Kunden bereitstellt, um auf die Daten zugreifen zu können.
 
Zuletzt bearbeitet:

OnDemand

Top Contributor
Ich will mich nicht groß einmischen, aber nur zum Verständnis:

Hersteller ist nicht gleich Kunde, oder?

Kann man sich das grob so vorstellen, dass es sich um eine Ersatzteil-DB handelt, die Ersatzteile von verschiedenen Herstellern für verschiedene Kunden verwaltet? Die Preise kommen von den Herstellern und werden von den Kunden aus deiner DB abgerufen? Stellen die Hersteller eine API zum Abruf zur Verfügung oder sitzt da einer vorm Computer und tippt Preislisten? Was legt fest, welcher Kunde auf welche Ersatzteile zugreifen kann? Kann ein Ersatzteil dann auch mehreren Kunden zugeordnet sein?

Jeder der 50 Hersteller stellt seine Daten in verschiedenen Formaten bereit, einer CSV per FTP, einer hat eine REST Api, ein anderer wiederum TXT. Wie der Hersteller die Daten erfasst, kein Schimmer. Wir holen die Daten ab, stellen Sie dem User in seine DB. Der User kann dann seine Ersatzteildaten bearbeiten (Beschreibungen erstellen etc, ähnlich wie in einem Webshop) Im Anschluss stellt unser Programm API bereit zu Werkstätten. Die Werkstätten können Bestände, Preise ziehen usw. sowie Bestellungen auslösen usw

Unser Kunde+User ist der zwischen Hersteller und Werkstatt. Unser User gibt uns an, welchen Hersteller er angebunden haben möchte und diese werden dann in seine DB importiert. Der User gibt uns quasi seine Logindaten vom Hersteller und wir holen die Daten ab. Jeder Hersteller-Kunde hat dabei aber verschiedene Artikel, Preise usw die der Hersteller für seinen Kunden (unseren User) verfügbar macht. Der Quelldaten-Aufbau ist bei jedem Hersteller unterschiedlich. User A und B von HerstellerXY haben die selbe CSV-Struktur, aber nicht den selben Inhalt.

Ein Ersatzteil wird auch mehreren Kunden zugewiesen, dass ist richtig.
 

temi

Top Contributor
Also gibt es drei Beteiligte: Hersteller, User (Kunde) und die Werkstätten (Kunden des Kunden?)?
Jeder der 50 Hersteller stellt seine Daten in verschiedenen Formaten bereit
Klingt nach Adaptern, die über einen oder mehreren Services die Daten abholen und in eine DB schreiben. Es werden aber keine einzelnen Teile dem Kunden zugeordnet sondern immer das gesamte Teilesortiment eines Herstellers?
 

OnDemand

Top Contributor
Genau, 3 beteiligte aber den 3. können wir ignorieren im Prinzip. Der hat mit dem import nix zu tun

Das was der Hersteller dem User ausgibt, wird ihm importiert
 

mrBrown

Super-Moderator
Mitarbeiter
Wenn ich den Workflow richtig verstanden habe gibt es einen Import von unterschiedlichen Quellen in eine DB. Daten aus der DB werden regelmäßig an die Kunden gepusht (oder die Kunden pullen) in derren tenant DB.
Wenn man die tenant DB weg lässt und die Kunden greifen auf die Zentrale DB zu hat man keinen Zeitversatz. U.u. kann im hintergrund regemäßig in die tenant DB gecacht werden, wenn die Verbindung wegfallen sollte.
Ich bin in Beiträgen immer nur von einer zentralen DB* ausgegangen, auf die direkter Zugriff besteht.

* Ob das jetzt eine zentrale DB für alle Tenants oder eine eigene DB pro Tenant gibt oder wie auch immer dort eine Zuordnung Record<->Tenant gelöst ist, ist dafür ziemlich egal.
 

temi

Top Contributor
Das was der Hersteller dem User ausgibt, wird ihm importiert
Haben die Daten von den unterschiedlichen Herstellern am Ende die selbe Struktur? Oder hat jeder Kunde seine eigene Struktur? Gibt es möglicherweise sogar Daten vom selben Hersteller mit unterschiedlicher Struktur, je nach Kunde?

Ich würde nach unabhängigen Prozessen suchen und so wie ich es verstehe, ist der Import der Daten von den Herstellern etwas, dass unabhängig vom Rest passiert und zwar eher automatisch.

Der zweite Prozess ist die Arbeit der Kunden mit den importierten Daten.

Der letzte der Abruf der bereitgestellten und bearbeiteten Daten durch die Werkstätten.
 

OnDemand

Top Contributor
Wenn die "gebuchten" Hersteller eines User mit dem Import fertig sind, haben die Daten die selbe Struktur. Alle Teile sind dann quasi ein "Teile-Objekt" mit Relationen und Attributen in der DB bei uns. Jeder Hersteller Service bereitet also die Daten so auf, dass sie der Entität schon entsprechen wenn er sie an den Master sendet (und genau während des Aufbereitens, werden Preise berechnet, bestimmte Parameter werden beachten die sich aus Einstellungen vom Nutzereingaben ergeben usw. diese Logik sollte in eine zentrale Stelle, statt in jeden Hersterller Service).

Ein Hersteller hat immer die gleiche Struktur für seine Kunden.
 

OnDemand

Top Contributor
zu dn den
Mal als Idee, wenn man beim Master bleiben will. Warum nicht Master & Einzel-Services entkoppeln. Anstelle das die Clients direkt mit dem Master reden pumpen die ihre Daten in eine MessageQueue rein (Kafka und was es da sonst noch so gibt).

Dann hast du den Vorteil:
* Master down => Clients können dennoch weiter nach Kafka Daten pumpen.
* Alle Clients pumpen zufällig gleichzeitig massive Datenmengen rein => Der Master braucht halt länger zum abarbeiten, aber die Clients merken nix davon.

@LimDul
Die Idee find ich irgendwie gut. Hab mir JMS mal ein wenig angeschaut. Bin mir noch nicht sicher ob folgendes gehen würde. Aber es wäre schon mal ein guter Plan:

Ich definiere ein Format wie die Daten in den MessageQueue, diese Struktur hat noch nichts mit dem "Ersatzteilprodukt gemein" sondern bringt alle verschiedene Herstellerdaten auf einen gemeinsamen Nenner.

Der HerstellerService liest die Daten in das format und sendet alle Daten mit einem als List oder jedes Produkt einzeln in den Queue.

Ein Listener im Master holt die Daten ab, holt die User Settings und erstellt die Produkte für die DB, berechnet Preise, legt Kategorien an usw.

Ein Vorteil der mir sofort dabei auffällt ist, dass das REST Request/Response entfallen würde. Derzeit fragt der Hersteller-Service beim Master ja jedesmal an, gibts den Artikel schon? Beim Anlegen eines neuen Produkts werden mehrere Abfragen gesendet wie "existiert der Hersteller schon? Wenn nein, anlegen und zurück geben" usw
Das könnte dann alles entfallen und in den Master eingebaut werden. Wenn ich dann eine Erweiterung einbaue zb dass der User im Frontend einstellt, "alle Teile mit Bestand 0, inaktiv setzen) könnte das der Master machen und ich muss es nicht in jedem Hersteller-Service einbauen.

in einem Kurs habe ich Apache JMS gesehen, welche JMS Implementierung sollte man sich unbedingt ansehen?
 

mrBrown

Super-Moderator
Mitarbeiter
Ein Vorteil der mir sofort dabei auffällt ist, dass das REST Request/Response entfallen würde.
Das ist mit der größte Vorteil dabei. Wenn alles nur über synchrones REST kommuniziert, hast du quasi einen verteilten Monilithen, fällt ein Teil aus, sind die anderen auch meist betroffen. Über Messaging hast du das Ganze entkoppelt, limitierender Faktor ist nur die Queue, die quasi beliebig skaliert werden kann.
Das könnte dann alles entfallen und in den Master eingebaut werden.
Potentiell kann dann auch der „Master“ aufgeteilt werden, die API zum Abfragen der Daten und die Verarbeitung von Teilen sind ja auch verschiedene Anwendungsfälle.


in einem Kurs habe ich Apache JMS gesehen, welche JMS Implementierung sollte man sich unbedingt ansehen?
Die Implementierung ist fast egal, an JMS kann man nahezu jede Message Queue irgendwie anbinden. Von RabbitMQ über Kafka bis zu Amazon SQS hast du da quasi völlig freie Wahl.
 

OnDemand

Top Contributor
Vielen Dank! Glaube das geht nun in die richtige Richtung. Ich spiele damit grad ein wenig rum, was mit auffällt ist , dass es lange dauert :D Ich setze 5000 Messages ab, die brauchen über 2 Minuten bis alle drin sind.

Spontan noch paar vielleicht doofe Fragen dazu, die sich sicher auch irgendwann von selbst beantworten wenn ich mich mehr in das Thema einlese.

- Wenn ich 10 verschiedene User habe, müsste ich 10 verschiedene Queues erzeugen oder einen Queue für Import (neue Artikel) und die Message so designen, dass der Tenant, also Nutzername drin enthalten ist, auf die der Master dann reagieren könnte? Oder könnte ich jeden Hersteller als "Topic" anlegen und darunter mehrere Queues?

- Kann ich das Apache Artemis als "Email-Postfach" sehen, spricht gibt n Posteingang mit den Messages, der Consumer holt die irgenwann ab und weg sind sie?

- Wo speichert Artemis Apache Dings die Messages ab? Als serialisierte Objekte auf der Platte? Dann dürfte eine SSD Pflicht sein danit das schön schnell geht.
 

Dukel

Top Contributor
Du kannst für jeden Hersteller ein Topic erstellen und die User (Kunden) abonieren eben die Topics, die sie gekauft haben.
 

OnDemand

Top Contributor
Du kannst für jeden Hersteller ein Topic erstellen und die User (Kunden) abonieren eben die Topics, die sie gekauft haben.

Abonieren, heißt dass auf dieses Topic ein Listener hört?

Ah scheinbar macht das JmsTemplate irgendwas was das Senden verlahmt, mit folgendem Code geht das senden Ratz Fatz

Code:
 public void run(String... arg0) throws Exception {

        ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61616");
        cf.setPassword("nico");
        cf.setUserName("nico");
        cf.setCopyMessageOnSend(false);
        Connection connection = cf.createConnection();
        connection.start();

        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Topic topic = session.createTopic("test.topic");
        final MessageProducer producer = session.createProducer(topic);


        for (int i = 0; i < 1000000; i++) {
            TextMessage message = session.createTextMessage("Test:" + i);
            producer.send(message);
        }
connection.close();
    }
 

mrBrown

Super-Moderator
Mitarbeiter
- Wenn ich 10 verschiedene User habe, müsste ich 10 verschiedene Queues erzeugen oder einen Queue für Import (neue Artikel) und die Message so designen, dass der Tenant, also Nutzername drin enthalten ist, auf die der Master dann reagieren könnte? Oder könnte ich jeden Hersteller als "Topic" anlegen und darunter mehrere Queues?
Potentiell gibts da beliebig viele Möglichkeiten, in deinem Fall würde ich eher zu einer Queue pro Kunde tendieren. Da fehlt aber allen hier vermutlich das Domänenwissen :)

Wenn ich dich richtig verstanden habe, fragt ein Hersteller-Service die Daten beim Hersteller sowieso konkret für einen Kunden ab?
Also ein Hersteller-Service fragt beim Hersteller die Daten einmal für Kunde A ab, dann für Kunde B, dann für Kunde C?


- Kann ich das Apache Artemis als "Email-Postfach" sehen, spricht gibt n Posteingang mit den Messages, der Consumer holt die irgenwann ab und weg sind sie?
Der kennt generell zwei Modi, Queue und Topic. Queue entspricht eher dem Brief, der wird abgeschickt und hat dann genau einen Empfänger, und die Topic entspricht eher dem Radio-Beitrag, wer grad zuhört, bekommt die Nachricht mit.

- Wo speichert Artemis Apache Dings die Messages ab? Als serialisierte Objekte auf der Platte? Dann dürfte eine SSD Pflicht sein danit das schön schnell geht.
https://activemq.apache.org/components/artemis/documentation/ :) uU ist auch die Variante ohne Persistenz passend.
 

OnDemand

Top Contributor
Jupp genau, pro Kunde wird beim Hersteller angefragt, da jeder andere Preise haben könnte usw.

wenn der Master Service offline ist, sammeln sich ja die Daten auf oder? Sobald ich den Service starte legt der listener los- so wars grad jedenfalls im Test.
Die queue löschen sich nicht automatisch richtig? Wenn ein Kunde den Service nicht mehr nutzt, kann auch der queue weg.

im Test war der queue dann halt leer.

glaube diese Variante könnte ich auch nutzen um Änderungen weiter zu geben.
Derzeit triggert ein trigger in eine andere Tabelle wenn sich preis und bestand ändert.
Die Daten werden dann abgeholt und abgearbeitet.

Wenn eine Message abgeholt ist, ist sie weg oder?
Fragen über Fragen 🤪
 

mrBrown

Super-Moderator
Mitarbeiter
Jupp genau, pro Kunde wird beim Hersteller angefragt, da jeder andere Preise haben könnte usw.
Dann würde ich eine Queue pro Kunde nutzen (oder eine Queue für alle Kunden zusammen, Kunde wäre dann ein Attribut des Events).

wenn der Master Service offline ist, sammeln sich ja die Daten auf oder? Sobald ich den Service starte legt der listener los- so wars grad jedenfalls im Test.
Ja, das ist der Sinn der Queue. Die Listener holen sich die Daten dann, wenn sie grad können, ob das "jetzt" oder in drei Tagen ist, ist für die Queue egal.
Die queue löschen sich nicht automatisch richtig? Wenn ein Kunde den Service nicht mehr nutzt, kann auch der queue weg.

im Test war der queue dann halt leer.
Ja, Queues muss man schon bewusst löschen, ansonsten ist die Queue halt leer vorhanden.

glaube diese Variante könnte ich auch nutzen um Änderungen weiter zu geben.
Derzeit triggert ein trigger in eine andere Tabelle wenn sich preis und bestand ändert.
Die Daten werden dann abgeholt und abgearbeitet.
Ja, wobei es dann Sinn macht, erst die "fertigen Daten" in die "Master"-Datenbank zu schreiben. Unfertige Daten in die Datenbank zu schreiben, dann ein Event zu publishen, woraufhin genau diese Daten geändert werden, hat wenig Sinn.

Wenn eine Message abgeholt ist, ist sie weg oder?
Wenn man Queues nutzt ja. Wobei sich da auch Transaktionen nutzen lassen, sodass Messages im Fehlerfall nicht verloren gehen.
Ist das ein Problem für einen deiner Anwendungsfälle?
 

OnDemand

Top Contributor
Problem nicht wirklich, wenn ein Ersatzteil verloren geht wird’s dann halt beim nächsten mal angelegt. Aber sollte möglichst nicht vorkommen am besten
 

OnDemand

Top Contributor
Noch ne Frage hierzu, könnte aber auch etwas OT sein:
Angenommen ich sende 10000 Messages an den Queue, jede Message enthält Ein TeileDto mit artikelnummer, Bestand, Preis und als Atrtibut hat die Message noch den Usernamen usw

Ein anderer Listener hört auf darauf und muss alle Bestände und Preise abgleichen, wenn sich ein Bestand oder Preis geändert hat. Zb wäre der andere Service dafür verantwortlich, das Werkstattprogramm zu informieren "hier hast du neuen Preis"

Wie kann ich das ganze performant umsetzen? Alle 10000 Messages nehmen und für jedes DTO:

Code:
UpdateDto updateDto = Select bestand, preis from parts where sku = sku
if(updateDto.getBestand != message.getBestand){
    repository.updateBestand(sku, message.getBestand);
    sendNewMessage(); //um event zu feuern
}
halte ich für super unperformant. Ich meine mal gelesen zu haben, dass es mit einem Interceptor möglich ist, der ein Event feuert wenn ein Update auch was updated hat. Aber auch dann wäre das nicht viel performanter. Ich müsste trotzdem jedes Teil updaten um zu erfahren ob sich was geändert hat.

Code:
for(UpdateDto updateDto : message.getUpdateDtoList(){
   repository.updateBestand(sku, message.getBestand);
   //hier dann irgendwie das Event feuern
}

Hat jemand ne Idee?
 

mrBrown

Super-Moderator
Mitarbeiter
Was hältst du denn an welcher Stelle denn für unperformant? Dass du für jeden Artikel prüfen musst, ob sich der Preis geändert hat, und das jeweils eine SQL-Abfrage bedeutet?


Wenn du die Abfrage wirklich brauchst, kommst du nicht drum herum, du kannst nur versuchen den Overhead kleiner zu machen.

Möglich wäre es, mehrere "Teile" zu einer Message zusammenzufassen, statt 10.000 Einzel-Messages gibt es dann eine Message mit 10.000 Einträgen (oder 100 x 100). Problem ist dann natürlich dass diese X Teile auch zusammen verarbeitet werden müssen, gibts nach der Hälfte einen Fehler, verlierst du entweder die restlichen oder musst alle noch mal machen.

Ansonsten kann man es sich auch überlegen, ob man überhaupt prüfen muss, ob der Bestand sich geändert hat. Ist es den zusätzlichen Roundtrip wert oder reicht es vielleicht, wenn man dann sagt "der Bestand hat sich von 10 Artikeln auf 10 Artikel" geändert?

Und man kann natürlich skalieren. Statt einem Service, der die Daten der Queue verarbeitet, kann man auch 100 nutzen - das ist ein Vorteil des Messaging-Systems, du kannst jede Komponente quasi beliebig skalieren.

Gibt sicherlich auch andere Ansätze die denkbar wären, wenn man die konkreten Probleme kennt, kann man da deutlich mehr zu sagen.


Wie ist es denn aktuell gelöst? Das müsste ja jetzt auch schon ein Problem sein, die Überprüfung hat ja die Ursache nicht in dem Event-basierten Ansatz.
 

mihe7

Top Contributor
Wenn eine SQL-DB dahinterliegt, fällt mir spontan noch die Möglichkeit ein, per JDBC ein UPDATE mit einer WHERE-Klausel abzusetzen und am Rückgabewert zu prüfen, ob überhaupt etwas aktualisiert wurde. Aber: premature optimization...
 

OnDemand

Top Contributor
Aktuell machen wir stumpf ein Update auf den Bestand, egal ob geändert oder nicht. Ein Trigger triggert dann wenn sich der Bestand geändert hat in eine andere Tabelle. Ein anderer Service holt dann aus der Tabelle raus, was getriggert wurde und sendet es weiter
 

mrBrown

Super-Moderator
Mitarbeiter
Wofür ist denn die Info "PreisBestand hat sich geändert" zusätzlich zu dem "das ist der aktuelle PreisBestand" nötig?
 

mrBrown

Super-Moderator
Mitarbeiter
Und wofür ist relevant, dass zu wissen? Also, gibt es an irgendeiner Stelle die Notwendigkeit, wirklich zu wissen, dass der Preis sich geändert hat, weil manche Effekte nur dann auftreten dürfen? Sowas wie eine info an den Kunden, dass der Preis sich geändert hat, das sollte natürlich nicht stündlich mit dem gleichen Preis kommen. Sowas wie 'aus dem Einkaufspreis den Verkaufspreis' berechnen ist ja erstmal unabhängig von der Änderung und hängt nur von dem aktuellem Preis ab.



Die Info über die Änderung kann aber natürlich in dem Fall auch direkt der Hersteller-Service speichern, und dieser gibt direkt die Info raus, dass es eine Änderung gab.
 

mihe7

Top Contributor
@NicoDeluxe Ich meinte etwas wie UPDATE parts SET bestand=:bestand WHERE sku=:sku AND bestand <> :bestand, dann per int changedRows = pstmt.executeUpdate() sich die Zahl der geänderten Zeilen (0 oder 1) zurückgeben lassen und ggf. Event feuern.
 

mrBrown

Super-Moderator
Mitarbeiter
@NicoDeluxe Ich meinte etwas wie UPDATE parts SET bestand=:bestand WHERE sku=:sku AND bestand <> :bestand, dann per int changedRows = pstmt.executeUpdate() sich die Zahl der geänderten Zeilen (0 oder 1) zurückgeben lassen und ggf. Event feuern.
Entspricht doch seinem eigenem Vorschlag, oder übersehe ich etwas?

Ich meine mal gelesen zu haben, dass es mit einem Interceptor möglich ist, der ein Event feuert wenn ein Update auch was updated hat. Aber auch dann wäre das nicht viel performanter. Ich müsste trotzdem jedes Teil updaten um zu erfahren ob sich was geändert hat.
 
Ähnliche Java Themen

Ähnliche Java Themen

Neue Themen


Oben