Microservices StrukturPlanung

OnDemand

Top Contributor
Das Empfängersystem ist nicht unter unserer Kontrolle, daher gibts welche die können wir zuballern und andere muss man vorsichtig sein :D
Das mit dem Update sieht gut aus, so werd ich es umsetzen.

Mit dem Preis und Bestand kann man so sehen, dass der Kunde nur dann informiert werden soll wenn es auch eine Änderung gab.

Vielleicht könnte man im Herstellerservice eine Map vorhalten mit <sku,bestand> und beim einlesen mit der map abgleichen obs ne Änderung gabe, dann spart man sich das senden der unötigen Messages
 

mrBrown

Super-Moderator
Mitarbeiter
Das Empfängersystem ist nicht unter unserer Kontrolle, daher gibts welche die können wir zuballern und andere muss man vorsichtig sein :D
Und die bekommen die Daten dann einfach per Post-Request oder so geschickt?


Vielleicht könnte man im Herstellerservice eine Map vorhalten mit <sku,bestand> und beim einlesen mit der map abgleichen obs ne Änderung gabe, dann spart man sich das senden der unötigen Messages
Das wäre sinnvoll, wobei „Map“ dann ein beliebiges Etwas sein kann, das irgendwie Key-Value-Paare speichern kann :) da geht ja alles vom fetten SQL-Server über den schlanken Key-Value-Store bis zur nur im Arbeitsspeicher liegenden Map.

Würde nicht wundern, wenn es schon irgendeinen Key-Value-Store/Message-Broker für genau den Anwendungsfall gibt; man gibt beliebige Dinge rein und raus kommen nur geänderte Werte, das ist ja nichts Domänen-Spezifisches.
 

OnDemand

Top Contributor
Genau, die bekommen dann ein Request auf ne API. Eine Map gefällt mir spontan schon mal, aber wenn der Hersteller Service down war, muss die Map erstmal wieder initialisiert werden.

Jetzt kam aber noch eine Anforderung dazu :D Die Bestände, Preise wo sich geändert haben, sollen abgespeichert werden damit daraus Statistiken generiert werden können und man nachverfolgen kann, welche Änderungen sich wann ergeben haben. Oh man es wird nicht einfacher
 

mrBrown

Super-Moderator
Mitarbeiter
Eine Map gefällt mir spontan schon mal, aber wenn der Hersteller Service down war, muss die Map erstmal wieder initialisiert werden.
Ist es schlimm, wenn im Fehlerfall dann zwei mal ein „Preis geändert auf 10“ kommt?
Wenn ja, dann einfach irgendwas persistentes nutzen, ansonsten reicht es ja wenn die mit leerer Map starten.

Jetzt kam aber noch eine Anforderung dazu :D Die Bestände, Preise wo sich geändert haben, sollen abgespeichert werden damit daraus Statistiken generiert werden können und man nachverfolgen kann, welche Änderungen sich wann ergeben haben. Oh man es wird nicht einfacher
Warum schwer? Einfach ein weitere Service, der das entsprechende Event mitbekommt, der Rest des Systems ist davon ja unabhängig :)
Man muss nur dir Art der Queue/Topic entsprechend wählen.
 

OnDemand

Top Contributor
Stimmt. Versuch grad in das Thema Topic/Queue einzusteigen. Kann man die Messages irgendwie gruppieren?
Wenn ich 3 Hersteller Queries habe und jeweils 5 Nutzer, dann habe ich da im schlimmsten Fall 10.000 x 5 Messages. Da kann man ja kaum was debuggen. Zb welcher User evtl hängen geblieben ist oder so
 

OnDemand

Top Contributor
Hab da noch was :/ Es muss zwingend mit jedem "Rundlauf" geprüft werden ob ein Ersatzteil überhaupt noch in der CSV/TXT vorhanden ist. Manche Hersteller nehmen einfach Artikel aus dem Sortiment ohne zu informieren. Aktuell haben wir es so:

Import beginnt, alle Parts werden tempStatus = 0 gesetzt
Bei jedem Bestandsupdate wird das 0 wieder auf 1 gesetzt
am Ende, werden alle mit 0 die übrig geblieben sind (weil kein Update bekommen) deaktiviert.

ging hin und wieder in die Hose und es hat alle deaktiviert :D
 

OnDemand

Top Contributor
Das geht leider nicht, weil die User in unserem Programm Änderung an den Daten vornehmen können. Zum Beispiel Namen, Beschreibungen usw. Bearbeiten
 

mrBrown

Super-Moderator
Mitarbeiter
Versuch grad in das Thema Topic/Queue einzusteigen. Kann man die Messages irgendwie gruppieren?
Wenn ich 3 Hersteller Queries habe und jeweils 5 Nutzer, dann habe ich da im schlimmsten Fall 10.000 x 5 Messages. Da kann man ja kaum was debuggen. Zb welcher User evtl hängen geblieben ist oder so
Naja, du gruppierst durch die Queue/Topic. (Wobei ich satt pro Hersteller eine eher pro User eine wählen würde.

Ansonsten bleibt dir nur Losging, Tracing und Metrics. Zumindest sowas wie ein User bleibt hängen fällt damit auf.

Hab da noch was :/ Es muss zwingend mit jedem "Rundlauf" geprüft werden ob ein Ersatzteil überhaupt noch in der CSV/TXT vorhanden ist. Manche Hersteller nehmen einfach Artikel aus dem Sortiment ohne zu informieren. Aktuell haben wir es so:
Jeder Herstellerservice speichert einfach die Artikel-Rohdaten, nach außen gibt er dann einfach nur noch Änderungen bzw Löschungen. Also deine Variante mit Map, nur dass das ganze persistent sein muss.
 

LimDul

Top Contributor
Jeder Herstellerservice speichert einfach die Artikel-Rohdaten, nach außen gibt er dann einfach nur noch Änderungen bzw Löschungen. Also deine Variante mit Map, nur dass das ganze persistent sein muss.
Das wäre auch die Variante, die ich beim lesen der Anforderungen bevorzugen würde. Den irgendeiner muss ja den Abgleich machen. Und das sieht - bei der Datenmenge - nicht so aus, als würde man das zentral machen wollen.

Grundsätzlich wäre mein Rat, setz dich mal in Ruhe hin und zeichne mal den kompletten Datenfluss auf (Ohne zu Entscheiden, wer was wo macht und speichert). Angefangen bei Daten werden vom Hersteller gelesen, Daten werden transformiert, Daten werden auf Änderungen gerprüft, Daten werden an Kunden ausgeliefert.

Und dann überlegst du dir, wo man da sinnvolle Schnitte einziehen kann.
 

OnDemand

Top Contributor
Wie wäre es, wenn ich die Rohdaten je als object auf die platte speichere und das beim Import abgleiche Mit equals. Wenn der Bestand des neuen Objekts dann anders ist, sollte equals doch false geben und ich weiss, was sich geändert hat und sende das object an den Broker und speichere die neue Version auf die SSD.
gibt zwar viele files aber ist simpel

ich nutze Lombock mit @Data das erstellt ja immer die aktuellste hash und equals methode, sollte eigentlich klappen. Hab noch nie objekte verglichen 😅
 
Zuletzt bearbeitet:

Dukel

Top Contributor
Naja, du gruppierst durch die Queue/Topic. (Wobei ich satt pro Hersteller eine eher pro User eine wählen würde.

Wenn mehrere User den gleichen Hersteller abonnieren werden duplizierte Daten verschickt.
D.h. Artikel 1-10 von Hersteller A kommt in fünf Topics (für User 1-5), Artikel 1-10 von Hersteller B kommen in fünf Topics für User 1,2,7,8,10,...

Sonst würden Artikel 1-10 von Hersteller A in ein Topic kommen und User 1-5 lesen diesen Topic, Hersteller B kommt in ein Topic und User 1,2,7,8 und 10 lesen diese Topics.
 

mrBrown

Super-Moderator
Mitarbeiter
Wenn mehrere User den gleichen Hersteller abonnieren werden duplizierte Daten verschickt.
D.h. Artikel 1-10 von Hersteller A kommt in fünf Topics (für User 1-5), Artikel 1-10 von Hersteller B kommen in fünf Topics für User 1,2,7,8,10,...

Sonst würden Artikel 1-10 von Hersteller A in ein Topic kommen und User 1-5 lesen diesen Topic, Hersteller B kommt in ein Topic und User 1,2,7,8 und 10 lesen diese Topics.
So wie ich in verstanden habe, werden die Daten eines Herstellers spezifisch für einen konkreten Nutzer abgefragt, Artikel 1 kann also für Nutzer 1 Preis 5 haben, für Nutzer 2 aber Preis 6:
Jupp genau, pro Kunde wird beim Hersteller angefragt, da jeder andere Preise haben könnte usw.
 

mrBrown

Super-Moderator
Mitarbeiter
Wie wäre es, wenn ich die Rohdaten je als object auf die platte speichere und das beim Import abgleiche Mit equals. Wenn der Bestand des neuen Objekts dann anders ist, sollte equals doch false geben und ich weiss, was sich geändert hat und sende das object an den Broker und speichere die neue Version auf die SSD.
gibt zwar viele files aber ist simpel

ich nutze Lombock mit @Data das erstellt ja immer die aktuellste hash und equals methode, sollte eigentlich klappen. Hab noch nie objekte verglichen 😅
Bastle sowas nicht selber, sondern nehm ne passende Datenbank dafür ;)
 

OnDemand

Top Contributor
Jupp das ist richtig, dass jeder andere Preise haben kann, evtl werden auch andere Bilder usw ausgegeben. Daten werden vermutlich auch doppelt ausgegegeben, aber das ist leider so
 

OnDemand

Top Contributor
Hab den Import für einen Hersteller und einen Eintrag aus der CSV mal skzizziert, das Pinke mal schauen mit welcher Variante wir das umgesetzt bekommen. DB oder Serialisieren etc. Jeder User muss dabei zum anderen parallel laufen. Ist vermutlich nicht die sinnvollste Skizze.

Wenn eine Änderung festgestellt wird, sollte auch nur die Änderung in die Message geschrieben werden.

Wenn eine Änderung festgestellt wurde, stelle ich des mir so vor, dass die Message folgendes enthält:

Body: ???
Properties an der Message:
„sku“:1234
“stock“: 5
“ekPreis“:546,90


wenn sich der Preis nicht geändert hat, würde ich den auch nicht an die Message hängen. Der Consumer kann prüfen ob ein eKPreis, stock übergeben wurde. Wenn nicht haben diese Werte keine Änderung. Im Prinzip sind es nur 4-5 Properties die uns interessieren ob was geändert wurde, daher fände ich es unnötig das gesamte Produkt zu übergeben.

Man könnte auch ein UpdateTeileDto als json in den Body schreiben bei nem Update, wäre vielleicht eleganter.

Bei der Neuanlage eines Teils, müsste eben das Teil in den Body.

Die Queues würde ich in dem Beispiel je Hersteller 2 machen: Einen für Import und einen für Updates. Gefällt mir noch nicht wirklich. Aber wenn ich je Kunden einen Query machen würde, müsste Ich ja den Consumer jedesmal Updaten wenn ein neuer Kunde kommt oder kann man die Queues irgendwie dynamisch einem Listener hinzufügen?



1591675270978.png
 

OnDemand

Top Contributor
Bastle sowas nicht selber, sondern nehm ne passende Datenbank dafür ;)
eine richtige DB fällt mE aus, wenn ich den Service auf einen anderen Server ziehen muss, ist es relativ aufwändig da die DB aufzusetzen. Mit meiner Serialisierungsvariante wäre das schneller erledigt.
Der Service würde einfach die Struktur im Dateisystem bei nem Import auf dem neuen Server wieder anlegen und fertig
 

mrBrown

Super-Moderator
Mitarbeiter
eine richtige DB fällt mE aus, wenn ich den Service auf einen anderen Server ziehen muss, ist es relativ aufwändig da die DB aufzusetzen. Mit meiner Serialisierungsvariante wäre das schneller erledigt.
Der Service würde einfach die Struktur im Dateisystem bei nem Import auf dem neuen Server wieder anlegen und fertig
DB hat man mit passendem Tooling mit einer einzigen Aktion aufgesetzt ;) wenn das Umziehen einer DB Deutlich mehr Aufwand als das umziehen von zig Dateien ist, macht man irgendwas falsch.
 

OnDemand

Top Contributor
hab das jetzt mal mit madb gemacht, klappt zufriedenstellend und ist 1 datei je user.Ne echte DB ist sooo viel overhead im Moment.

Was ich mich noch frage ist, wie die Queries abgearbeitet werden. Der Listener merkt das eine Message in den Queue eingestellt wurde und holt sie ab. Wenn nun 100.000 Messages rein gehen, wie reagiert der Listener? Macht der alle nacheinander oder wie ich es unter asynchron verstehe, parallel? Der macht doch dann aber nicht 100.000 Threads auf?! Wie kann ich mir das vorstellen?

Ich frage deshalb weil es vorkommen kann, dass 100.000 Messages eingestellt werden mit dem Hinweis auf Betandsänderung. Dann würden 100.000 UPDATE Queries auf die DB gehen. Das wäre bisschen viel schätz ich.
 

mrBrown

Super-Moderator
Mitarbeiter
Was ich mich noch frage ist, wie die Queries abgearbeitet werden. Der Listener merkt das eine Message in den Queue eingestellt wurde und holt sie ab. Wenn nun 100.000 Messages rein gehen, wie reagiert der Listener? Macht der alle nacheinander oder wie ich es unter asynchron verstehe, parallel? Der macht doch dann aber nicht 100.000 Threads auf?! Wie kann ich mir das vorstellen?

Ich frage deshalb weil es vorkommen kann, dass 100.000 Messages eingestellt werden mit dem Hinweis auf Betandsänderung. Dann würden 100.000 UPDATE Queries auf die DB gehen. Das wäre bisschen viel schätz ich.
Eine Mischung aus beidem, auf Consumer-Seite wird üblicherweise ein Thread-Pool genutzt, wenn grad kein Thread frei ist, wird auch keine neue Message verarbeitet.
 

OnDemand

Top Contributor
Eine Mischung aus beidem, auf Consumer-Seite wird üblicherweise ein Thread-Pool genutzt, wenn grad kein Thread frei ist, wird auch keine neue Message verarbeitet.
Ok danke. Ist der von Haus aus da oder muss ich einen erstellen 🤓 laut Google gibt es die Möglichkeit einen zu erstellen, das werd ich wohl machen um die Anzahl threads unter Kontrolle zu haben
 

Schuriko

Bekanntes Mitglied
Naja es sind glaub ich inzwischen fast 50 Stunden Video - Material. Aber Spring Boot fängt doch schon realtiv früh an. Glaub schon im 2ten Kapital ("Building a Spring Boot Web-App") wird damit angefangen. Und zieht sich wie ein roter Faden durch den gesammten Kurs durch.
 

mrBrown

Super-Moderator
Mitarbeiter
Ja, JMS kommt vor, relativ weit hinten. (Mit "Building a Spring Boot Web-App" hat das allerdings nichts zu tun ;) )
 

Schuriko

Bekanntes Mitglied
Ja, JMS kommt vor, relativ weit hinten. (Mit "Building a Spring Boot Web-App" hat das allerdings nichts zu tun ;) )
Das Kapitel über JMS seperat ja, auf JMS geht er aber ab der Lektion 90 (von über 500) ein. Und wie ich in dem anderen Thread schon geschrieben habe ist der Titel: "Vom Anfänger zum Guru" leicht übertrieben. Aber für den ersten Einstieg bis Fortgeschrittenen ist der Kurs schon sehr gut.

Ansonsten geb ich dir Recht, Spring Boot hat mit JMS nichts zu tun, ich persönlich würde sogar soweit gehen, zu Behaupten es sind zwei unterschiedliche Paar Schuhe.

Er hatte aber geschrieben, er findet nichts zu Spring Boot.
 
Zuletzt bearbeitet:

OnDemand

Top Contributor
Hab jetzt mal ActiveMQConnectionFactory.setUseAsyncSend(true) gesetzt aber das brauch mir immer noch zu lange 30 Messages pro Sekunde ca. Da muss doch mehr gehen o_O
 

OnDemand

Top Contributor
Jetzt hab ich wie folgt gesendet:

Java:
 taskExecutor.execute(() -> {
   jmsTemplate.convertAndSend(JmsConfig.IMPORT_QUEUE, productImportDto);
});

Alle 40.000 Teile wurden in wenigen Sekunden (unter 5) an den Queue geschickt. Krass!
Aber irgendwie hat das nichts mit dem Pooling zu tun. In der Properties kann ich einstellen was ich will (oder auch eine Bean erstellen) ohne den TaskExector dümpelt es vor sich her.

Code:
spring.activemq.user=nico
spring.activemq.password=nico
spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=1000
spring.activemq.broker-url=tcp://localhost:61616

Hat noch jemand n Tipp wie der Pool korrekt genutzt wird?
 

OnDemand

Top Contributor
Ums senden gehts mir grad.

Die folgenden Settings in der properties, bewirken dass 40k Teile in 6 min an den Broker geschickt werden. Das ist doch ein guter Schnitt find ich. Vorallem wenn ich bedenke, dass mehrere Services auf einem Server laufen. Wenn ich dann zig Threads sende hab ich Angst, dass der Server überlastet, der Server wo der Broker läuft muss das ja auch alles fressen können wenn da mehrere Services drauf ballern.

spring.jms.cache.enabled=true
spring.jms.cache.consumers=true
spring.activemq.broker-url=tcp://localhost:61616

Meinen Mac hab ich grad zum abstürzen gebracht mit 2000 Threads (TaskExecutor) :D
 

mrBrown

Super-Moderator
Mitarbeiter
Auf Producer-Seite ist es unsinnig, das Senden in einen extra Task-Executor auszulagern, da kannst du einfach den aktuellen Thread für nutzen. (Außer, das Senden dauert wirklich extrem lange pro Nachricht, was aber eher nicht der Fall sein dürfte)
 

OnDemand

Top Contributor
Hm kommt drauf an wie man schnell definiert, er hat so 30 pro Sek gemacht. Das ist gefühlt langsam. Mit dem og, caching gehts aber schneller (150 pro Sekunde), damit werd ich leben.

Beim Listener liegts auch so bei 100 pro sekunde wenn ich die message nur ausgebe. Das ist auch ok denk ich.

Aufm Server gehts dann bestimmt nochmal ein wenig flotter.
 

OnDemand

Top Contributor
Nun überlege ich doch nochmal um, bezgl der Datenbank. MapDB ist nice, aber ich kann nicht einfach in die DB schauen was evtl kaputt ist etc.
Nun überlege ich doch auf eine DB zu gehen:

product_db
table_hersteller1
table_hersteller2
usw

Die Tabellen so simpel wie möglich:

sku
ekprice
tenant
name
beschreibung
stock
ean
mpn
usw

Das dumme daran ist dann natürlich, dass die Daten 100 fach vorkommen würden. (Wäre in mapdb auch ) Also Artikel 12345 wäre für 10 User, 10 mal in der Tabell. Evtl 10 x identisch, evtl auch 10 mal mit je verschiedenem Preis. Eigentlich müsste ich Datenbank "richtig" aufbauen sodass alle Werte die die anders sein können in eine eigene Tabelle stecken.

zb
table_price
id
tenant
ekPreis

Dann wäre das sauber, aber ist aufwändiger. Wenn ich das so mache, könnte ich auch gleich die Daten in die jeweilige tenante DB schreiben, was aber wiederrum bedeuten würde ich müsste die Logiken (Preis berechnen, Stati setzen usw) in den Hersteller Service einbauen. Wenn ich dann was ändere muss ich das bei jedem Hersteller.

Hier drehe ich mich irgendwie im Kreis.

Ich könnte auch einfach wie folgt vorgehen:

Erster Import legt ne Map an Map<sku,product> und speichert die lokal als Datei.
bei jedem weiteren Import wird die Datei geladen und die darin enthaltenen Produkte werden abgeglichen / ersetzt (update) ich bekomme Änderungen am Preis usw mit, welche ich dann an JMS senden kann.

Die Map würde dann (vermutlich?) im RAM liegen. Die größte derzeit hat 200mb, wenn ich die Daten so speichere als Map ist die Datei 20MB groß. Wenn ich sie lade bedeuted das, dass diese mit 20MB im RAM liegt oder wird das irgendwie "dynamsich" gehandhabt?
 

temi

Top Contributor
Das dumme daran ist dann natürlich, dass die Daten 100 fach vorkommen würden. (Wäre in mapdb auch ) Also Artikel 12345 wäre für 10 User, 10 mal in der Tabell. Evtl 10 x identisch, evtl auch 10 mal mit je verschiedenem Preis.
Ist denn nur der Preis unterschiedlich, oder noch mehr? Man könnte ja eine Tabelle mit Artikelstammdaten haben und weitere Tabellen mit pro Kunde variablen Daten. Ungefähr folgende Tabellen:

Tabelle Kunden
Tabelle Artikelstammdaten
Tabelle Preise (mit FK_Kunde und FK_Artikel)
 

mrBrown

Super-Moderator
Mitarbeiter
Das dumme daran ist dann natürlich, dass die Daten 100 fach vorkommen würden. (Wäre in mapdb auch ) Also Artikel 12345 wäre für 10 User, 10 mal in der Tabell. Evtl 10 x identisch, evtl auch 10 mal mit je verschiedenem Preis.
Welche Daten können denn vom Kunden abhängen, nur der Preis oder auch anderes?

Ich persönlich würde bei einer Tabelle bleiben, der Aufwand für Normalisierung (wenn es nicht sogar schon ausreichend normalisiert ist?) ist es in dem Fall wohl nicht wert.


Wenn ich das so mache, könnte ich auch gleich die Daten in die jeweilige tenante DB schreiben, was aber wiederrum bedeuten würde ich müsste die Logiken (Preis berechnen, Stati setzen usw) in den Hersteller Service einbauen. Wenn ich dann was ändere muss ich das bei jedem Hersteller.
Nur weil du einen Schritt weit gehst, musst du ja nicht gleich den Marathon laufen :)

Ich könnte auch einfach wie folgt vorgehen:

Erster Import legt ne Map an Map<sku,product> und speichert die lokal als Datei.
Das wäre wieder die „selber basteln“ Variante, stattdessen einfach die Datenbank nehmen dürfte sinnvoller sein (in Hinblick auf ACID etc), es muss ja keine Relationale Datenbank sein.
 

OnDemand

Top Contributor
Die Daten können verschieden sein Bilderlinks können fehlen, Preise anders, Beschreibungen können abweichen.

Wenn wir den aktuellen Hersteller nehmen mit 40k Datensätzen, wären wir bei 100 Kunden bei 400k Einträgen in der Tabelle. Mit solchen Daten hab ich noch keine Erfahrung gemacht. Ist das viel? Keine Ahnung :D
 

mrBrown

Super-Moderator
Mitarbeiter
Die Daten können verschieden sein Bilderlinks können fehlen, Preise anders, Beschreibungen können abweichen.
Dann dürften die Daten direkt schon in 4. (BC? 5.?) Normalform vorliegen.
Schlüsselkandidat ist (Artikel-Nr, Kunde), davon sind alle anderen abhängig.


Wenn wir den aktuellen Hersteller nehmen mit 40k Datensätzen, wären wir bei 100 Kunden bei 400k Einträgen in der Tabelle. Mit solchen Daten hab ich noch keine Erfahrung gemacht. Ist das viel? Keine Ahnung :D
400k Zeilen dürften kein Problem sein.
Überschlags einfach mal grob in Byte, wie viele Daten sind’s denn pro Artikel, irgendwas im unteren Kilobyte-Bereich? Und dann ist generell kaum Last auf der DB, keinerlei joins, nur einfach Insert/Update/Select mit Index.
 

OnDemand

Top Contributor
Danke, ich teste das jetzt mal. Mal schauen was der db Server sagt. Dazu werde ich versuchen einen Interceptor einzubauen, der mir sagt welche werte sich geändert haben dann kann ich daraus gleich die Events feuern.

Ist doch richtig, dass Hibernate bei save() entweder updated oder neu anlegt, richtig? Geht das auch bei .saveAll() dann könnte ich gleich ne List speichern, spart vielleicht auch noch etwas Last?
Der Key müsste dann wie du sagst tenant und sku sein.
 

OnDemand

Top Contributor
Jo das läuft. Lokale DB 40k Teile in 30 Sekunden mit save all und batch.
Allerdings gehts auf dem Liverserver mal wieder nicht so schnell. Da ist doch garantiert wieder irgenwas falsch konfiguriert :/
 

OnDemand

Top Contributor
Jap, aber auch nach 5 minuten kommt in der remote db nix an :( Die remote DB hat eine 1gbit Anbindung und ich hier 200.000 das muss doch flutschen oder?
 
Ähnliche Java Themen

Ähnliche Java Themen

Neue Themen


Oben