# Microservices StrukturPlanung



## OnDemand (5. Jun 2020)

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 (5. Jun 2020)

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 (5. Jun 2020)

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 (5. Jun 2020)

NicoDeluxe hat gesagt.:


> 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.


----------



## kneitzel (5. Jun 2020)

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 (5. Jun 2020)

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 (5. Jun 2020)

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 (5. Jun 2020)

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 (5. Jun 2020)

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 (5. Jun 2020)

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 (5. Jun 2020)

@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.


----------



## mrBrown (5. Jun 2020)

NicoDeluxe hat gesagt.:


> @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.



NicoDeluxe hat gesagt.:


> 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.





NicoDeluxe hat gesagt.:


> Messaging ist das hier nehm ich an? https://spring.io/guides/gs/messaging-jms/


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


----------



## OnDemand (5. Jun 2020)

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 (5. Jun 2020)

NicoDeluxe hat gesagt.:


> 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.)




NicoDeluxe hat gesagt.:


> 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.)



NicoDeluxe hat gesagt.:


> 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 




NicoDeluxe hat gesagt.:


> 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 (5. Jun 2020)

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 (5. Jun 2020)

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 (5. Jun 2020)

Dukel hat gesagt.:


> 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 (5. Jun 2020)

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 (5. Jun 2020)

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.


----------



## OnDemand (5. Jun 2020)

temi hat gesagt.:


> 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 (5. Jun 2020)

Also gibt es drei Beteiligte: Hersteller, User (Kunde) und die Werkstätten (Kunden des Kunden?)?


NicoDeluxe hat gesagt.:


> 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 (5. Jun 2020)

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 (5. Jun 2020)

Dukel hat gesagt.:


> 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 (5. Jun 2020)

NicoDeluxe hat gesagt.:


> 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 (6. Jun 2020)

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 (7. Jun 2020)

zu dn den


LimDul hat gesagt.:


> 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?


----------



## OnDemand (7. Jun 2020)

Das hier find ich sehr sehr interessant! https://hackernoon.com/scaling-micr...ueues-spring-boot-and-kubernetes-9ba4b0e48bdf


----------



## mrBrown (7. Jun 2020)

NicoDeluxe hat gesagt.:


> 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.


NicoDeluxe hat gesagt.:


> 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.




NicoDeluxe hat gesagt.:


> 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 (7. Jun 2020)

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  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 (7. Jun 2020)

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


----------



## OnDemand (7. Jun 2020)

Dukel hat gesagt.:


> 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


```
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 (7. Jun 2020)

NicoDeluxe hat gesagt.:


> - 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? 




NicoDeluxe hat gesagt.:


> - 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.



NicoDeluxe hat gesagt.:


> - 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 (7. Jun 2020)

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 (7. Jun 2020)

NicoDeluxe hat gesagt.:


> 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).



NicoDeluxe hat gesagt.:


> 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.


NicoDeluxe hat gesagt.:


> 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. 



NicoDeluxe hat gesagt.:


> 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.



NicoDeluxe hat gesagt.:


> 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 (7. Jun 2020)

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


----------



## mrBrown (7. Jun 2020)

NicoDeluxe hat gesagt.:


> 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


Die Message wird erst aus der Queue entfernt, wenn du bestätigst, dass sie korrekt verarbeitet ist. Verloren gehen sollte dort nichts.


----------



## OnDemand (7. Jun 2020)

ach das ja tippi toppi 🤩 muss ich mir unbedingt näher ansehen


----------



## OnDemand (8. Jun 2020)

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:


```
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.


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

Hat jemand ne Idee?


----------



## mrBrown (8. Jun 2020)

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 (8. Jun 2020)

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 (8. Jun 2020)

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


----------



## Dukel (8. Jun 2020)

Musst du jedes mal 10.000 Elemente in die Queue schicken und nicht z.B. nur die, die sich geändert haben?


----------



## mrBrown (8. Jun 2020)

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


----------



## OnDemand (8. Jun 2020)

Ich weiß zum Zeitpunkt des Abholens noch nicht, welche Daten sich geändert haben beim Hersteller :/


----------



## OnDemand (8. Jun 2020)

mrBrown hat gesagt.:


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


Wir leiten die Änderungen an andere Systeme weiter. Wenn wir immer alles weiterleiten wäre das zu viel und unnötig Last auf das Empfängersystem, daher wollen wir nur Änderungen übertragen


----------



## mrBrown (8. Jun 2020)

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.


----------



## mrBrown (8. Jun 2020)

NicoDeluxe hat gesagt.:


> Wir leiten die Änderungen an andere Systeme weiter. Wenn wir immer alles weiterleiten wäre das zu viel und unnötig Last auf das Empfängersystem, daher wollen wir nur Änderungen übertragen


Empfängersysteme unter eurer Kontrolle?


----------



## mihe7 (8. Jun 2020)

@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 (8. Jun 2020)

mihe7 hat gesagt.:


> @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?



NicoDeluxe hat gesagt.:


> 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.


----------



## mihe7 (8. Jun 2020)

mrBrown hat gesagt.:


> Entspricht doch seinem eigenem Vorschlag


Äh, ... ja


----------



## Dukel (8. Jun 2020)

Evtl. solltest du den Workflow einmal grafisch darstellen und erläutern an welcher Stelle du Probleme hast.


----------



## OnDemand (8. Jun 2020)

Das Empfängersystem ist nicht unter unserer Kontrolle, daher gibts welche die können wir zuballern und andere muss man vorsichtig sein 
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 (8. Jun 2020)

NicoDeluxe hat gesagt.:


> Das Empfängersystem ist nicht unter unserer Kontrolle, daher gibts welche die können wir zuballern und andere muss man vorsichtig sein


Und die bekommen die Daten dann einfach per Post-Request oder so geschickt?




NicoDeluxe hat gesagt.:


> 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 (8. Jun 2020)

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   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 (8. Jun 2020)

NicoDeluxe hat gesagt.:


> 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.



NicoDeluxe hat gesagt.:


> Jetzt kam aber noch eine Anforderung dazu  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 (8. Jun 2020)

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 (8. Jun 2020)

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


----------



## thecain (8. Jun 2020)

Lösch halt alles und importier alles nochmal


----------



## OnDemand (8. Jun 2020)

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


----------



## mrBrown (8. Jun 2020)

NicoDeluxe hat gesagt.:


> 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.



NicoDeluxe hat gesagt.:


> 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.


----------



## OnDemand (8. Jun 2020)

http://www.mapdb.org/ sieht schonmal gut aus


----------



## LimDul (8. Jun 2020)

mrBrown hat gesagt.:


> 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 (8. Jun 2020)

Wirst lachen, sitz grad mitm ipad und zeichne einen plan 😅


----------



## OnDemand (8. Jun 2020)

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 😅


----------



## Dukel (8. Jun 2020)

mrBrown hat gesagt.:


> 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 (8. Jun 2020)

Dukel hat gesagt.:


> 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:


NicoDeluxe hat gesagt.:


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


----------



## mrBrown (8. Jun 2020)

NicoDeluxe hat gesagt.:


> 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


----------



## Dukel (8. Jun 2020)

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



Jeder Hersteller könnte andere Preise haben.



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



Jeder Kunde könnte andere Preise bekommen.

-> Am besten wir warten auf das Diagramm und raten nicht weiter.


----------



## OnDemand (9. Jun 2020)

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 (9. Jun 2020)

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?


----------



## OnDemand (9. Jun 2020)

mrBrown hat gesagt.:


> 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 (9. Jun 2020)

NicoDeluxe hat gesagt.:


> 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 (11. Jun 2020)

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 (11. Jun 2020)

NicoDeluxe hat gesagt.:


> 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 (11. Jun 2020)

mrBrown hat gesagt.:


> 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


----------



## mrBrown (11. Jun 2020)

NicoDeluxe hat gesagt.:


> 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


Du nutzt Spring, oder? Von Haus aus ist immer einer da, ein eigener ist aber sinnvoller.


----------



## OnDemand (11. Jun 2020)

genau spring boot. Hmm find da iwie nix gescheites zu. Ist das n Taskexecutor und der sendet das in seiner Methode oder?


----------



## Schuriko (11. Jun 2020)

NicoDeluxe hat gesagt.:


> genau spring boot. Hmm find da iwie nix gescheites zu. Ist das n Taskexecutor und der sendet das in seiner Methode oder?


Hatten wir das nicht vor kurzem???? 😁😁😁 https://www.java-forum.org/thema/verstaendnisfrage-dto-spring-boot.188551/#post-1224383 Thompsen doch für den Anfang einen guten Einstieg, oder was fehlt dir?


----------



## OnDemand (11. Jun 2020)

kommt das da drin vor? Soweit bin ich noch nicht vorgedrungen scheinbar


----------



## Schuriko (11. Jun 2020)

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.


----------



## Schuriko (11. Jun 2020)

Hab nochmal nachgeschaut sind inzwischen 57 Stunden. Er erweitert den Kurs ja in unregelmässigen Abständen.


----------



## mrBrown (11. Jun 2020)

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


----------



## Schuriko (11. Jun 2020)

mrBrown hat gesagt.:


> 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.


----------



## OnDemand (11. Jun 2020)

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


----------



## OnDemand (11. Jun 2020)

Schuriko hat gesagt.:


> Er hatte aber geschrieben, er findet nichts zu Spring Boot.



öh echt? Hast falsche verstanden, finde nix zum Thema JMS in Threads senden


----------



## OnDemand (11. Jun 2020)

Jetzt hab ich wie folgt gesendet:


```
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.


```
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?


----------



## mrBrown (11. Jun 2020)

Geht es dir grad um das Senden oder das Empfangen?


----------



## OnDemand (11. Jun 2020)

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)


----------



## mrBrown (11. Jun 2020)

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 (11. Jun 2020)

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 (12. Jun 2020)

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 (12. Jun 2020)

NicoDeluxe hat gesagt.:


> 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 (12. Jun 2020)

NicoDeluxe hat gesagt.:


> 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.




NicoDeluxe hat gesagt.:


> 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 



NicoDeluxe hat gesagt.:


> 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 (12. Jun 2020)

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


----------



## mrBrown (12. Jun 2020)

NicoDeluxe hat gesagt.:


> 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.




NicoDeluxe hat gesagt.:


> 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


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 (12. Jun 2020)

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 (12. Jun 2020)

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 :/


----------



## mrBrown (12. Jun 2020)

NicoDeluxe hat gesagt.:


> 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 :/


Datenbank und Service laufen auf unterschiedlichen Systemen und müssen übers Netzwerk kommunizieren?


----------



## OnDemand (12. Jun 2020)

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?


----------



## OnDemand (12. Jun 2020)

Lese ich da unterschwellig heraus, dass ich die DB auf dem selben Server installieren soll?


----------



## mrBrown (12. Jun 2020)

NicoDeluxe hat gesagt.:


> 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?


Wenn da irgendwas 5min dauert, läuft da zumindest irgendwas nicht richtig...

Entweder weil ein Request ewig lange dauert, oder weil es sehr viele requests innerhalb einer Transaktion sind. Klappt das ganze denn mit einzelnen Artikeln?



NicoDeluxe hat gesagt.:


> Lese ich da unterschwellig heraus, dass ich die DB auf dem selben Server installieren soll?


Man sollte zumindest drüber nachdenken, ob und warum man die DB auf einem extra Server laufen lässt (und die gleiche Überlegung dann natürlich für den Fall, dass man beides auf einem Server laufen hat).

Dann kann man sinnvoll entscheiden. Die DB einfach auf einem externen Server laufen lassen "weil das macht man halt so" ist nicht sinnvoll


----------



## OnDemand (12. Jun 2020)

wir haben extra einen starken server für die ganzen dbs, die werden da immer brav gesichert usw. Und der Adminaufwand hält sich in grenzen mit einem Server. Hab jetzt mal ne mongo aufgesetzt bei irgend nem free gedöns. Da importiert es, zwar auch nicht übelst schnell aber es tut sich was. Hmm muss der Datenbankmensch wohl mal gucken was da los ist.


----------



## OnDemand (12. Jun 2020)

Ah jetzt hab ich noch was interessantes. Ich hab nen ping von teilweise 1000ms zum db server. Das trägt natürlich nicht positiv bei


----------



## mrBrown (12. Jun 2020)

NicoDeluxe hat gesagt.:


> wir haben extra einen starken server für die ganzen dbs


Ist halt die Frage, ob ein extra starker Server sinnvoller ist, als uU mehrere kleine...

Bei den einzelnen Herstellerservices, dir ziemlich genau voraussagbare und planbare Last erzeugen, gäbe es vielleicht bessere Möglichkeiten.
Mit einer zentralen DB fängt man sich uU die gleichen Probleme wieder ein. (alle Hersteller-Services und der Master-Service arbeiten gleichzeitig => hohe Last auf zentraler DB; zentrale DB hat Aussetzer => Alle Services sind betroffen, auch wenn sie eigentlich völlig problemlos noch arbeiten könnten)

Das soll jetzt kein "Nehm auf jeden Fall einzelne Datenbanken pro Service" sein, aber man sollte es zumindest in beiden Fällen gut begründen können.



NicoDeluxe hat gesagt.:


> die werden da immer brav gesichert usw. Und der Adminaufwand hält sich in grenzen mit einem Server.


Sowas gehört eh automatisiert, dann ist es kaum ein Unterschied, ob einer oder 100 Server 



NicoDeluxe hat gesagt.:


> Hab jetzt mal ne mongo aufgesetzt bei irgend nem free gedöns.


Dafür kann man zB Docker nutzen, das ist prädestiniert für solche Fälle


----------



## OnDemand (12. Jun 2020)

verstehe was du meinst danke. Wenn ich zb 5 services habe die auf einem laufen und dann muss ich einen service auf einen anderen server ziehen, weil so viele user kommen oder sonst was, dann muss ich alle daten mit nehmen. So schieb ich den service wo anders hin, starte ihn und fertig. hmmm


----------



## OnDemand (12. Jun 2020)

Auf nem anderen Server gehts auch nicht schneller. Tjoa dann bleibt wohl nur lokale DB für jeden Service 
Hab mal das Looging aktiviert für saveAll gibt es folgendes aus:
Generated identifier: component
Loading entity:...
select product0_...
Done entity load...

das dauert halt..


kann das mit der ID zu tun haben?
public class Product {

```
@EmbeddedId
private ProductId id;

...
}

public class ProductId implements Serializable {
    @Column
    private String productsSku;
    @Column
    private String tenant;
}
```


----------



## thecain (12. Jun 2020)

Wenn du eine Sekunde Ping hast, brauchst du den Code nicht mehr gross anschauen.

Da scheint irgendwas am Netzwerk nicht zu stimmen.


----------



## OnDemand (13. Jun 2020)

Selbst auf einem linux server, der einen ping zur db von 15ms hat gehts nicht schneller. Hätte ich nicht gedacht, dass ein Netzwerk so starken Einfluss haben kann. Von mir lokal zum Server ok, aber von einem Server zum Server...die haben beide 1gibt hin und her.

Dann bleibt mir ja nur noch die Services mit einer DB auf eine Maschine zu packen. Das wird a bissl teuer.  Cloudzeug wie AWS will ich nicht nutzen, ist mir zu kompliziert und Geld haben die ohnehin schon genug, möchte meinen lokalen Anbieter unterstützen, dann muss ich mit dem irgend ne Lösung finden.

Dumme Frage; H2 nutzen mit Speichern auf der Platte ist keine gute Idee oder?


----------



## OnDemand (13. Jun 2020)

Ah ne h2 wird ja glaube gelöscht bei neustart. oook dann hab ich ein Problem


----------



## mrBrown (13. Jun 2020)

NicoDeluxe hat gesagt.:


> Selbst auf einem linux server, der einen ping zur db von 15ms hat gehts nicht schneller. Hätte ich nicht gedacht, dass ein Netzwerk so starken Einfluss haben kann. Von mir lokal zum Server ok, aber von einem Server zum Server...die haben beide 1gibt hin und her.


Der Ping hat vor allem dann nen Einfluss, wenn es sehr viele kleine Pakete sind. Wenn die 40.000 Artikel alle einzeln gesendet werden, bist du mit einfachem Ping schon bei 40.000*15ms = 10min. Deshalb eben Batching, damit du weniger einzelne Requests hast.



NicoDeluxe hat gesagt.:


> Dann bleibt mir ja nur noch die Services mit einer DB auf eine Maschine zu packen. Das wird a bissl teuer. Cloudzeug wie AWS will ich nicht nutzen, ist mir zu kompliziert und Geld haben die ohnehin schon genug, möchte meinen lokalen Anbieter unterstützen, dann muss ich mit dem irgend ne Lösung finden.



Die Services laufen doch sicherlich schon irgendwo? Probier vorher mal aus, ob überhaupt ein größerer Server notwendig wäre. Die Anforderungen sind da an die Datenbank sehr gering. Du hast völlig planbare Last, brauchst also keinerlei Reserven, und die Last ist auch noch beliebig steuerbar, besser kann es gar nicht laufen



NicoDeluxe hat gesagt.:


> Dumme Frage; H2 nutzen mit Speichern auf der Platte ist keine gute Idee oder?
> [...]
> Ah ne h2 wird ja glaube gelöscht bei neustart. oook dann hab ich ein Problem


Mit H2 kann man auch Problemlos auf der Platte speichern. Die Datenbank nur im RAM halten ist nur eine der möglichen Optionen.


----------



## LimDul (13. Jun 2020)

NicoDeluxe hat gesagt.:


> Ah ne h2 wird ja glaube gelöscht bei neustart. oook dann hab ich ein Problem


Nö, wenn du bei h2 als Protokoll File und nicht Memory nimmst, wird die Datei nicht gelöscht.

Ich hab es jetzt nicht im Detail verfolgt - aber man kann sich auch die Frage stellen, wie "schlimm" wäre ein Datenbankverlust beim Herstellerservice? Man könnte in der Architektur des Systems zwei verschiedene "Varianten" der Kommunikation Hersteller Service => Master vorsehen.

a) Differentiell (Der Hersteller Service schickt nur die Änderungen, die er aus seiner lokalen DB berechnet rübert)
b) Voll (Der Hersteller Service schickt die kompletten Daten rüber, der Master schmeisst alle alten des Hersteller Service weg und übernimmt sie neu)

Dann kann man es sich leisten beim Hersteller Service auf eine leichtgewichtige Datenbank ohne besonders große Sicherheit in Richtung Backups und Co setzen - denn im Falle eines Problems, macht man erst mal einen Vollabgleich und ist dann wieder sauber.


----------



## OnDemand (13. Jun 2020)

Ich habe jetzt mal postgres auf einem testserver installiert und den service da drauf > 10 Sek für 40k Produkte. Also lag es definitiv am Netzwerk. Hätte ich nicht gedacht.

Ich werde das also so machen mit einer "echten" Datenbank. Postgres hab ich zwar noch nie genutzt, wird aber mal Zeit es kennen zu lernen 

Nun noch eine Frage, wie würdet ihr die Infrastruktur aufbauen? Ich möchte die Services der Einfachheit halber als linux service installieren also kein Docker o.ä.

Wir haben derzeit micro server im Einsatz auf denen die Services verteilt sind (mehrere Services pro Server). Damit bin ich bisher eigentlich zufrieden Es gäbe nun aber auch eine Alternative, eine Art VM  in der Cloud. Wir könnten ein Template hinterlegen und beim deployen eines neuen Servers würde postgres, java usw automatisch installiert werden.

Je Service ein Server wäre bestimmt etwas übertrieben oder was meint ihr? Wenn es eng würde auf den Micro kann man ja immer noch umziehen. Wobei aber getrennt natürlich super sauber wäre.

Mein Plan ist jetzt wie folgt:

Artikel werden in die lokale Hersteller DB geladen. Beim Speichen schickt ein Interceptor eine Message mit dem Produkt an den Broker (entweder neu, preis geändert, stock geändert usw). Die Queues würde ich nach Fachlickeit sortieren, also Import-Queue, Update-Queue, Delete-Queue
Jeder Hersteller-Service stellt die Nachrichten dann in den entsprechenden Queue. Das sollte ActiveMQ abkönnen wenn da paar hundert tausend Messages zu verarbeiten sind oder (Hardware vorausgesetzt)? 

Der Master hat je Queue einen Listener und holt die Messages ab und verarbeitet den Inhalt. Den Master kann ich bei Bedarf sogar teilen oder duplizieren? Wenn ein Listener eine Message abgeholt hat, wird sie für andere Listener auf den selben Queue geblockt oder?

Im Master werden dann die Verarbeitungen vorgenommen und in die "echte" entgültige Kunden-DB geschrieben.

Over and out. Einwände sind gern gesehen


----------



## mihe7 (14. Jun 2020)

NicoDeluxe hat gesagt.:


> Ich möchte die Services der Einfachheit halber als linux service installieren also kein Docker o.ä.


Einfacher als mit docker geht's kaum - da ist der ganze Infrastrukturkäse bereits enthalten (insbesondere DNS, NAT (wobei NAT bremst), Load-Balancer im Swarm-Mode).


----------



## mrBrown (14. Jun 2020)

NicoDeluxe hat gesagt.:


> Nun noch eine Frage, wie würdet ihr die Infrastruktur aufbauen? Ich möchte die Services der Einfachheit halber als linux service installieren also kein Docker o.ä.
> 
> Wir haben derzeit micro server im Einsatz auf denen die Services verteilt sind (mehrere Services pro Server). Damit bin ich bisher eigentlich zufrieden Es gäbe nun aber auch eine Alternative, eine Art VM in der Cloud. Wir könnten ein Template hinterlegen und beim deployen eines neuen Servers würde postgres, java usw automatisch installiert werden.
> 
> Je Service ein Server wäre bestimmt etwas übertrieben oder was meint ihr? Wenn es eng würde auf den Micro kann man ja immer noch umziehen. Wobei aber getrennt natürlich super sauber wäre.


Ich würde das auch nicht ohne Container und zB Kubernetes aufbauen. Das ganze händisch zu managen dürfte einfach deutlich mehr Arbeit sein und kaum einen Vorteil bringen.


----------



## OnDemand (14. Jun 2020)

Kubernetes oder Docker hab ich bisher noch nie benutzt. Müsste ich mir erstmal ansehen :/


----------



## mrBrown (14. Jun 2020)

mindestens Docker lohnt sich ganz generell, auch zum entwickeln auf dem lokalen System.


----------



## OnDemand (14. Jun 2020)

Mein Serveradmin meint auch, docker angucken. Hab ich auf meiner Liste, aber nun möchte ich erstmal mit den Services voran kommen 

hast du ne Idee wie ich prüfe ob ein Artikel noch in der Datei enhalten ist? Hibernate hat doch auch irgend ne Annotation (find die nur nich) wo es automatisch einen Wert setzt, wenn updated wird. 

Dann könnte man doch eine Spalte status erstellen und vor jedem Import auf 0 setzen. Dann Alle drüber und die dann immer noch 0 haben, waren nicht mehr in der Datei enthalten.


----------



## mihe7 (14. Jun 2020)

NicoDeluxe hat gesagt.:


> Hibernate hat doch auch irgend ne Annotation (find die nur nich) wo es automatisch einen Wert setzt, wenn updated wird.


Meinst Du @PreUpdate udn @PostUpdate?



NicoDeluxe hat gesagt.:


> Dann könnte man doch eine Spalte status erstellen und vor jedem Import auf 0 setzen.


Du könntest beim Aktualisieren auch einfach ein Timestamp (Start des Imports) oder eine Versionsnummer (Import-Lauf-ID) setzen. Dann sparst Du Dir das vorherige auf 0 setzen.


----------



## OnDemand (14. Jun 2020)

Nö aber danke die kann ich ja auch nutzen  dann setze ich einfach status true in einer mit @PreUpdate annotierten Methode  Danke


----------



## mrBrown (14. Jun 2020)

NicoDeluxe hat gesagt.:


> Hibernate hat doch auch irgend ne Annotation (find die nur nich) wo es automatisch einen Wert setzt, wenn updated wird.


Ja, aber du die wird dir in Bezug auf gelöschte Einträge nichts bringen. Gelöscht und "nicht geändert" bewirken ja beide keine Versionsänderung.



NicoDeluxe hat gesagt.:


> Dann könnte man doch eine Spalte status erstellen und vor jedem Import auf 0 setzen. Dann Alle drüber und die dann immer noch 0 haben, waren nicht mehr in der Datei enthalten.


Ja, möglich wäre das. Alternativ Timestamp oder "Versionsnummer", die mit jedem Update steigt.

Eine andere Möglichkeit wäre, einfach alles als neue Werte in die DB zu schreiben (sodass alte Werte und nur Werte beide vorhanden sind), und dann  ein Diff aus alten und neuen Werten erstellen. (Die alten Werte danach dann noch löschen, sonst blähst du die DB unnötig auf.)
Damit bekämet du sowohl Änderungen als auch gelöschte Werte, und bräuchtest nur ein INSERT und ein SELECT.

EDIT: grob etwa so: http://sqlfiddle.com/#!9/38c8b4/6/0


----------



## mrBrown (15. Jun 2020)

Ich hab das mal getestet mit lokaler Postgres-DB (ohne Publishen über RabbitMQ, und mit nur Preis und Anzahl), das braucht konstant unter 10s für das „Berechnen“ der Änderungen von ~100_000 Artikel.

Ich stell den Code gleich mal Online und schreib was dazu.


----------



## OnDemand (15. Jun 2020)

Es gab eine Anforderung, dass Artikel wieder aktiviert werden können indem sie wieder in der Datei vorkommen. Manche GH nehmen die raus wenn sie für eine gewisse Zeit nicht zur Verfügung stehen. Mit dem Update kommen wir da gut klar und dem dem temp_status. Wenn Die Artikel wieder aktiviert werden, können wir drauf reagieren und den Artikel auch wieder aktiv setzen


----------



## mrBrown (15. Jun 2020)

Mr. Brown / demo · GitLab
					

GitLab.com




					gitlab.com
				




Statt Hibernate nutzt das JOOQ. Hibernate verursacht da relativ viel Overhead, den man nicht braucht, mit JOOQ läuft das deutlich leichtgewichtiger.

Erkennen der Änderungen wird gemacht, indem jeder Eintrag eine Versionsnummer bekommt, die DB kann dann die Änderungen "berechnen", etwa wie in dem SqlFiddle weiter oben. Den FULL OUTER JOIN kann man sicher noch optimieren, das Einfügen ist allerdings das deutlich langsamere.
Postgres läuft dabei mit weniger als 200Mb Ram (±, docker stats lag zumindest deutlich drunter.)


----------



## OnDemand (15. Jun 2020)

oh man das ist ja nett, danke für deine Hilfe. Hast ein Bier gut bei mir  schau ich mir dann mal an. Du nutzt Gitlab? Ich überlege Bitbucket abzusägen und auf github umzusteigen, hab mich aber noch nicht damit beschäftigt was es kostet usw.


----------



## mrBrown (15. Jun 2020)

NicoDeluxe hat gesagt.:


> Du nutzt Gitlab? Ich überlege Bitbucket abzusägen und auf github umzusteigen, hab mich aber noch nicht damit beschäftigt was es kostet usw.


u.a. GitLab und GitHub.

Gibts Gründe für nen Umstieg?


----------



## OnDemand (15. Jun 2020)

ne nich wirklich  Probier nur immer gern neues aus. 
Werde die Services dann auch jeweils als eigenes Repo checken. Derzeit hab ich ein Repo wo alle Services drin sind. Wobei ja Jira mit Bitbucket gut zusammenarbeiten kann (angeblich, ich bekomms nicht hin )


----------



## OnDemand (19. Jun 2020)

Halöööle 

Sitz grad vor folgender Situation:

Ein Scheduler wird jede Stunde aufgerufen und liest UserSettings. Diese Usersettings hängt er an eine Message. Der Listener holt das ab, macht seine Arbeit und schiebt die geänderten Produkte in einen anderen Queue und hängt die Settings wieder an und sendet die mit. Idee dabei ist, beim "UpdateListener" nicht pro Message die Settings jedesmal zu lesen um die DB zu schonen.

Dumm ist jetzt aber, dass wenn ich die UserSettings um ein Feld erweitere, die anderen Services noch das alte "UserSettings" Objekt kennen wor das neue Feld fehlt.

Heißt ich müsste jetzt jeden Service neu bauen und neu starten.

Ich könnte auch im UpdateService eine Map einfügen welche die UserSettings zwischen speichert, dann ist aber das Problem dass während der Laufzeit die UserSettings sich ändern können und in der Map falsche Einstellungen liegen.

Am einfachsten wäre es ja die UserSettings jedesmal frisch zu lesen, aber das frisst doch unheimlich Resource bei 10.000 Messages und mehr. 

Hat jemand ne andere Idee?


----------



## OnDemand (19. Jun 2020)

Ich könnte doch eigentlich die Settings als Map aufbauen

Map <String, Object> settings;

und darin

settings.put("calculate_price", true);
settings.put("update_stock", false);

So bleibts dynamisch. Wenn eine neue Einstellung dazu kommen, stecke ich die im Scheduler in die Map. Der UpdateService muss dann nur erweitert werden, den neuen Key zu kapieren


----------



## mrBrown (19. Jun 2020)

NicoDeluxe hat gesagt.:


> Ein Scheduler wird jede Stunde aufgerufen und liest UserSettings. Diese Usersettings hängt er an eine Message.


In welchem Service liegt der Scheduler und wer braucht die UserSettings?

Potentiell kann man völlig auf Scheduler verzichten. Eine Änderung der UserSettings fällt ja nicht plötzlich vom Himmel, sondern wird irgendwie ausgelöst - an der Stelle könnte man direkt das Event werfen.



NicoDeluxe hat gesagt.:


> Idee dabei ist, beim "UpdateListener" nicht pro Message die Settings jedesmal zu lesen um die DB zu schonen.


Was ist der UpdateListener?

Man kann die Settings auch einfach direkt im Service halten - wenn die Änderungen immer über ein Event kommen, muss der die nie aus der DB holen.



NicoDeluxe hat gesagt.:


> Dumm ist jetzt aber, dass wenn ich die UserSettings um ein Feld erweitere, die anderen Services noch das alte "UserSettings" Objekt kennen wor das neue Feld fehlt.
> 
> Heißt ich müsste jetzt jeden Service neu bauen und neu starten.


Das muss man bei jeder Änderung. Du musst nur drauf achten, dass die Änderung möglichst Abwärtskompatibel ist, größere Änderungen muss man dann uU über zwei Updates ausrollen.





NicoDeluxe hat gesagt.:


> Ich könnte auch im UpdateService eine Map einfügen welche die UserSettings zwischen speichert, dann ist aber das Problem dass während der Laufzeit die UserSettings sich ändern können und in der Map falsche Einstellungen liegen.
> 
> Am einfachsten wäre es ja die UserSettings jedesmal frisch zu lesen, aber das frisst doch unheimlich Resource bei 10.000 Messages und mehr.


Wie oben gesagt: der Service bekommt das einfach per Event, aus der DB muss das nie gelesen werden. Einfach direkt im Service halten, bei Änderungen kommt ein Event welches die Daten dann ändert.



NicoDeluxe hat gesagt.:


> Ich könnte doch eigentlich die Settings als Map aufbauen
> 
> [...]
> 
> So bleibts dynamisch. Wenn eine neue Einstellung dazu kommen, stecke ich die im Scheduler in die Map. Der UpdateService muss dann nur erweitert werden, den neuen Key zu kapieren


Den gleichen Effekt kannst du mit jeder Datenstruktur haben - du musst immer nur darauf achten, dass aktuelle Messages auch von eine Version zurück hängenden Services verstanden haben.
Die Messages selber müssen nur in einem „generischen“ Format vorliegen, also zB nicht die normale Java-Serialisierung.
Jeder Service deserialisiert sich das dann in das Format, welches er braucht.
Service 1 kann ein normales Java-Objekt draus machen, Service 2 ne Map, und Service 3 und C ein Struct.


----------



## OnDemand (19. Jun 2020)

Danke für deine (wieder) ausführliche Antwort. Der Scheduler ist ein Service der nur steuert welcher Hersteller wann importieren soll. Das haben wir ausgelagert damit neue Hersteller dazukommen können ohne irgendeinen anderen Service neustarten zu müssen. 

Hab es jetzt so gemacht, dass der Scheduler die Settings holt, eine Map draus macht und dem HerstellerService per JMS übergibt. Der HerstellerService  holt sich dann dort die Logindaten raus zb. 

Wenn der Hesteller fertig ist, gibt der Die Settings wieder mit an den "Master" der dann die anderen Settings braucht.

so kann ein User die Einstellungen ändern und beim nächsten Updatelauf werden die neuen Settings geladen und beachtet. Sollte erstmal reichen. Abwärtskompatibilität sollllllte erstmal noch kein Thema sein hoff ich. Werd ich im weiteren Verlauf merken


----------



## mrBrown (19. Jun 2020)

NicoDeluxe hat gesagt.:


> Der Scheduler ist ein Service der nur steuert welcher Hersteller wann importieren soll. Das haben wir ausgelagert damit neue Hersteller dazukommen können ohne irgendeinen anderen Service neustarten zu müssen.


Und was macht der Scheduler, was die Services nicht selbst könnten? Aktuell klingt das wie eine zentrale Abhängigkeit, die man nach Möglichkeit vermeiden will.



NicoDeluxe hat gesagt.:


> Hab es jetzt so gemacht, dass der Scheduler die Settings holt, eine Map draus macht und dem HerstellerService per JMS übergibt. Der HerstellerService holt sich dann dort die Logindaten raus zb.


Warum bekommt der Service die Daten nicht direkt, wenn die Daten erstellt/geändert werden?

Das regelmäßige schicken der Daten ist doch überflüssig - es muss nur sicher gestellt werden, dass der Service jeweils die aktuellen hat, dafür recht ja einmaliges Schicken bei Änderungen.



NicoDeluxe hat gesagt.:


> Wenn der Hesteller fertig ist, gibt der Die Settings wieder mit an den "Master" der dann die anderen Settings braucht.


Das klingt auch unnötig. Der Master kann die Daten auch einfach direkt bekommen, anstatt jedes Mal auf's Neue.

Ansonsten baut man sich nur einen verteilten Monolithen.


----------



## OnDemand (19. Jun 2020)

Der Scheduler informiert die Hersteller Services, dass sie arbeiten sollen. Dabei gibts paar Einschränkungen zb Wartungsmodus, dann darf kein Hersteller beginnen. Der Scheduler sendet dann keine Messages an die Hersteller. Zudem prüft er ob die Einstellungen valide sind, wenn nicht bekommt der User eine Info dass das Update aufgrund XXX nicht starten konnte.
Das @Scheduled und die Validation Prüfung könnte auch direkt in den Herstellerservice, aber dann hab ich so viele Stellen wo was angepasst werden müsste

Mir sind da auch noch ein paar zu viele Abhängigkiten, aber bekomme die nicht alle gelöst ohne dass es nachher mehr Aufwand ist wenn was neues eingebaut wird.


----------



## mrBrown (19. Jun 2020)

Sehr grob und unübersichtlich, aber ich hoffe man versteht es:


Jeder Service bekommt über Events (/Messages) das, was für ihn interessant ist, und speichert das alles lokal bei sich ab.

Der User-Service veröffentlicht alle Änderungen an Kunden-Daten, zB Login-Daten oder Preis-Berechnung. Hersteller und Master-Service subscriben sich an der Topic dafür.
Der Hersteller-Service interessiert sich zb für die Login-Daten eines Kunden für den Hersteller, wenn er das Event bekommt, und speichert alles was er baucht lokal bei sich ab.
Der Master-Service macht das gleiche für die Daten die ihn interessieren, zB die Preisberechnung.

Brauchen Master-/Hersteller-Service dann welche von den Daten, haben sie die lokal direkt verfügbar.



NicoDeluxe hat gesagt.:


> Der Scheduler informiert die Hersteller Services, dass sie arbeiten sollen.


Das könnten die Services auch einfach selbst machen, damit sind die tendenziell auch freier in der Entscheidung und können das zB von lokaler Last abhängig machen.



NicoDeluxe hat gesagt.:


> Dabei gibts paar Einschränkungen zb Wartungsmodus, dann darf kein Hersteller beginnen.


Ist der Wartungsmodus Teil der Business-Logik, also in der Fachlichkeit vorhanden, sowas wie "Hersteller X macht Urlaub, in der Zeit darf man keine Anfragen stellen"?
Oder eher auf Infrastruktur/Anwedungsseite, sowas wie "Hardware wird getauscht"?

Ersteres kann man auch einfach über Events löse, Service bekommt das Event über Start/Ende des "Wartungsmodus" und reagiert entsprechend.
Letzeres würd ich unabhängig davon lösen, und von der Business-Logik trennen.



NicoDeluxe hat gesagt.:


> Zudem prüft er ob die Einstellungen valide sind, wenn nicht bekommt der User eine Info dass das Update aufgrund XXX nicht starten konnte.


Warum muss das stündlich geprüft werden? Kann es passieren, das valide Daten plötzlich, ohne äußeres Ereignis, invalide werden?

Wenn Nein -> dann brauchts keine stündliche Prüfung, Invalide Daten sollten den Hersteller-Service auch gar nicht erreichen.
Wenn Ja -> Event für "Daten wieder gültig"/"Daten nicht gültig".


----------



## OnDemand (20. Jun 2020)

Guten Morgen,

oh man vielen Dank für Deine Mühe! Der Wartungsmodus ist eher von unserer Seite aus zu sehen, Hardwartausch ist ein gutes Bespiel.
Das stündliche prüfen der Einstellungen ist nötig, da der Kunde Schrott eingeben kann / Unlogische Einstellungen setzen. Das sollte eigentlich das Frontend verhindern aber soweit sind wir noch nicht.

Zu der Grafik: Verstehe ich es richtig, dass du die Settings jeden Herstellers im Hersteller Service speicherst und der Hersteller die Settings in sich anwendet? Zb Kunde hat eingestellt, dass alle Artikel mit Bestand 0 deaktiviert werden -  der Hersteller Service überprüft den Bestand beim einlesen und setzt auf inaktiv? So wäre es sehr logisch abgetrennt, was mich da aber stört ist wenn wir da an der Logik etwas ändern, muss das in jedem Herstellerservice nachgebaut werden. Das kann sehr aufwändig werden oder?
Daher die Idee diese unspezifischen Einstellungen (die ja für jeden Hersteller gleich sein können) in den Master auszulagern.

Du sendest in der Grafik die Artikeländerungen jeweils an einen Query eines Users, wie kommt man da mit nem Listener ran wenn während der Laufzeit ein neuer Kunde dazu kommt? Bisher kenne ich nur das statische Angeben von Desinantions in @JmsListener (destinaation="blabla-queue")


----------



## mrBrown (20. Jun 2020)

NicoDeluxe hat gesagt.:


> oh man vielen Dank für Deine Mühe! Der Wartungsmodus ist eher von unserer Seite aus zu sehen, Hardwartausch ist ein gutes Bespiel.


Dann würde ich das nicht über Messages abhandeln, die nutzt man besser für Domain-Logik.

Theoretisch kann man sich überlegen, ob es so einen "Wartungsmodus" überhaupt geben muss. In obigem Szenario kann man zur Laufzeit beliebig Services ergänzen oder entfernen, das ist für die Gesamt-Anwendung egal.



NicoDeluxe hat gesagt.:


> Das stündliche prüfen der Einstellungen ist nötig, da der Kunde Schrott eingeben kann / Unlogische Einstellungen setzen. Das sollte eigentlich das Frontend verhindern aber soweit sind wir noch nicht.


Und warum dann stündlich prüfen und nicht direkt beim Eingeben? Im Simpelste Fall ergänzt man den stündlichen Scheduler um ein (App-Server-internes) Event, welches das Prüfen auslöst. Das stündliche klingt zumindest nicht sehr sinnvoll.



NicoDeluxe hat gesagt.:


> Zu der Grafik: Verstehe ich es richtig, dass du die Settings jeden Herstellers im Hersteller Service speicherst und der Hersteller die Settings in sich anwendet? Zb Kunde hat eingestellt, dass alle Artikel mit Bestand 0 deaktiviert werden - der Hersteller Service überprüft den Bestand beim einlesen und setzt auf inaktiv? So wäre es sehr logisch abgetrennt, was mich da aber stört ist wenn wir da an der Logik etwas ändern, muss das in jedem Herstellerservice nachgebaut werden. Das kann sehr aufwändig werden oder?
> Daher die Idee diese unspezifischen Einstellungen (die ja für jeden Hersteller gleich sein können) in den Master auszulagern.


Jeder Service speichert genau die Daten, die er selbst braucht - was genau das für Daten sind kannst du ja frei definieren 

Das aktivieren/deaktivieren das Bestands kann auch oben durchaus im Master passiert (in dem Fall speichert sich der Master die Einstellungen dafür), das muss nicht der Herstelller-Service machen. Der Hersteller-Service würde sich dann aber sowas wie Login-Daten für den Hersteller speichern, oder für welche Kunden es überhaupt abgefragt wird.



NicoDeluxe hat gesagt.:


> Du sendest in der Grafik die Artikeländerungen jeweils an einen Query eines Users, wie kommt man da mit nem Listener ran wenn während der Laufzeit ein neuer Kunde dazu kommt? Bisher kenne ich nur das statische Angeben von Desinantions in @JmsListener (destinaation="blabla-queue")


Irgendwie lassen sich auch Listener dynamisch zur Laufzeit hinzufügen, aus'm Kopf hab ich allerdings keine Ahnung wie...

Kann man allerdings auch durch eine eine einzelne Queue ersetzen, solange der Kunde in der Message hinterlegt ist.


----------



## OnDemand (20. Jun 2020)

Auf kurz oder lang kann der Wartungsmodus weg, da hast Recht. Aktuell blockt er, dass Großhändler nochmal neu beginnen. Hauptgrund ist auch wenn wir ein Update eines Service machen. Da haben wir die Wartung eingeschaltet, gewartet bis alle fertig waren und den Service neu gestartet.

Hab jetzt das SettingsProblem mal wie folgt umgebaut:

Der Hersteller wird getriggert (Scheduler 9 Uhr zb) holt die Settings (api Login zb) und legt los. Wenn eine Productänderung festgestellt wurde (Interceptor) wird eine Message erstellt -> mit dem geänderten Wert, Username.

Im Listener:
Hab ich eine Map <String, Settings> in der Hauptklasse. Beim @JmsListener Aufruf wird geprüft ob da Settings drin sind für den User, wenn nein werden die frisch geholt. Zb nach einem Restart ist die Map ja erstmal wieder leer, also werden die aktuellen Settings geholt.

Im Frontend (muss noch gebaut werden, da kommt dann auch die eingabeprüfung rein damit erst gar kein Scheiß gespeichert wird) wird ein Event ausgelöst, wenn der User seine Daten neu speichert kommt nicht oft vor (1x Woche?)-> Message in das og Topic

Der Listener nimmt den Message Inhalt, prüft ob der User überhaupt diesen Wert geändert haben will (anhand der Settings aus der Map).
Zusätzlich habe ich einen @JmsListener auf eine Topic "import-settings-topic" welcher (siehe Frontend-Event) die Settingsdaten in der Map gegen die neuen austauscht.

Das sieht doch schon mal ziemlich nach deinem Bild aus und funktioniert soweit gut. 

Zum Thema Wartung fällt mir noch was ein:

Angenommen ich will den Master Updaten, weil neues Feature. Der arbeitet grad 100.000 Nachrichten ab. Wie kann ich dem sagen "Haaaaalt Stop" ich will dich neu starten ohne zu warten bis der iwie fertig ist


----------



## OnDemand (26. Jun 2020)

Hallo, hab hierzu noch ein Problemchen. Und zwar angenommen 2 User mit einem Hersteller. Der Hersteller ändert 42.000 Artikel jeweils den Bestand. 
Nun sendet der Herstellerservice 84.000 Messages. Der Consumer arbeitet aber erst den einen, dann den anderen User ab.

Das ist nich wirklich parallel. Nun habe ich 2 Ansätze:

1. Irgendwie die geänderten Daten im HerstellerService sammeln, diese in eine List stecken und für jeden User die List senden, macht dann 2 Messages mit je einer List. Bei 2 Usern ok kein Problem aber bei 200 Usern, ist das auch wieder nicht parallel (dann müsste man den Consumer klonen oder sonst was vermutlich)

2. Jeder User bekommt einen eigenen Queue in den alle Änderungen rein gehen, Bestand, Namensänderungen , Preisänderungen und es gibt für jeden UserQueue einen Consumer. Das klingt mir irgendwie am logischsten. Aber ich finde keine Möglichkeit dynamisch Listener auf Queues zu erstellen, ohne dass ich explizit die Destinaion angebe.


----------



## mihe7 (27. Jun 2020)

Soweit ich das verstehe: die Queue dient nur als Kommunikationskanal. Davon unabhängig kannst Du die Arbeit auf mehrere Threads verteilen. Da das JMS-Zeug nicht thread-safe ist, musst Du entweder einen JMSContext je Thread verwenden oder Du entkoppelst den Spaß auf Producer-Seite über eine Queue. Auf der Consumer-Seite dagegen kann der Listener dagegen die Worker-Threads erstellen. Ich weiß nicht, wie das in Spring ist, in Java EE gibt es einen Thread-Pool für die Message Driven Beans, man kann also einfach festlegen, wie viele Instanzen an MDBs die Nachrichten parallel verarbeiten (s. z. B. https://www.baeldung.com/ejb-message-driven-bean-concurrency)


----------



## OnDemand (11. Jul 2020)

Hallo zusammen, möchte hier gern nochmal drauf zurück kommen.

Habe es jetzt so, dass die daten "dumm" und realtiv wenig normalisiert in der Hersteller DB liegen. Änderungen werden dort mittels Envers getracked und in eine eigene tabelle geschieben, soweit so gut.

Sobald neue Produkte reinkommen werden die in einen Query "neue Artikel" gschoben mit dem user als property in der Message, das selbe mit den Änderungen.

Allerdings sind mit einerm Kunden da jetzt schon 400MB Daten in der DB :/ das wird natürlich immer mehr je mehr User diesen Hersteller wollen. Irgendwann sind da millionen von Datensätzen, da hab ich die Befürchtung, dass das immer langsamer wird.

Nun zum ersten Problem: 
Wenn ich jedes neue Produkt einzeln sende, arbeitet der Listener parallel Messages ab und legt Kategorien zb doppelt an bzw verursacht einer einen Fehler, duplicate Entry bla. Kann man das überhaupt in den Griff bekommen da die Threads ja parallel arbeiten.

Am liebsten wäre es mir, wenn jeder User einen eigenen Query hätte, das geht auf Producerseite aber ich kann auf der Consumerseite zur Laufzeit keinen Listener auf einen userQuery hinzufügen.

Hab mir schon Bücher und Videos reingezogen, aber ich bekomme die Services nicht wirklich sinnvoll unter einen Hut ohne Daten doppelt zu haben oder doppelte Arbeit zu haben wenn ich etwas einbaue

Hat noch jemand eine Idee wir man die ganzen Importservices unter einen Hut bekommen könnte?


----------



## mrBrown (13. Jul 2020)

NicoDeluxe hat gesagt.:


> Allerdings sind mit einerm Kunden da jetzt schon 400MB Daten in der DB :/ das wird natürlich immer mehr je mehr User diesen Hersteller wollen. Irgendwann sind da millionen von Datensätzen, da hab ich die Befürchtung, dass das immer langsamer wird.


Die Daten brauchst du aber doch in jedem Fall?

Durch die Trennung in verschiedene Services speicherst du sie zwar doppelt, aber man bekommt halt nichts kostenlos, in diesem Fall gewinnt man dadurch Schnelligkeit und Ausfallsicherheit.

Man kann versuchen die gespeicherten Daten möglichst zu minimieren. Reicht es uU, einfach nur einen Hash zu speichern? Man sieht dann zwar nur noch, ob sich Daten geändert haben, und nicht mehr welche, aber vielleicht ist das ja egal?



NicoDeluxe hat gesagt.:


> Wenn ich jedes neue Produkt einzeln sende, arbeitet der Listener parallel Messages ab und legt Kategorien zb doppelt an bzw verursacht einer einen Fehler, duplicate Entry bla. Kann man das überhaupt in den Griff bekommen da die Threads ja parallel arbeiten.
> 
> Am liebsten wäre es mir, wenn jeder User einen eigenen Query hätte, das geht auf Producerseite aber ich kann auf der Consumerseite zur Laufzeit keinen Listener auf einen userQuery hinzufügen.


Ich wüsste nicht, warum du nicht Listener zur Laufzeit erzeugen können sollst? Irgendwie geht das in jedem Fall, ich müsste auch mal nachgucken, aber grundsätzlich gibt JMS das her.



NicoDeluxe hat gesagt.:


> Hab mir schon Bücher und Videos reingezogen, aber ich bekomme die Services nicht wirklich sinnvoll unter einen Hut ohne Daten doppelt zu haben oder doppelte Arbeit zu haben wenn ich etwas einbaue


Daten doppelt haben ist dabei ja ganz bewusst so - erst dadurch gewinnt man die Unabhängigkeit und Ausfallsicherheit zur Laufzeit. Bis auf den größeren Speicherplatzbedarf scheint das in deinem Fall ja auch kein Problem zu sein?


----------



## OnDemand (13. Jul 2020)

Hi,
der Speicherplatz macht mir da eher weniger sorgen, kostet ja nix mehr heututuage. Eher die Anzahl der Zeilen, wenn ich mir den einen Hersteller anschaue, der hat 200k Artikel x 10 User (da jeder andere Preise, usw haben kann) dann dauern die Updates ewig oder? Ich könnte die Tabelle der Hersteller auch pro Kunde anlegen, dann hab ich aber da wieder bisschen overhead, dann müsste ich mich ums löschen der DB und anlegen kümmern wenn ein neuer User kommt. Andere Möglichkeit wäre, einmal alle Daten abzuspeichern mit den Daten die unser Testlogin vom Hersteller bekommt und dann die kundenspezifischen Änderungen abspeichern, aber da kann es wieder passieren dass ein Kunde Artikel XYZ nicht bekommen darf (ist dann in seinem API, CSV Feed nicht enthalten)

Mit dem Listener bekomm ich echt nicht gebacken, ich hätte am liebsten für jeden User einen eigenen Query (macht das Sinn?) Übersichtlich ist es auch jeden Fall. Dann könnte der Grohandelservice schön in jeden "Briefkasten" für den Kunden pumpen und ein Listener arbeitet nur dieses Query nach und nach ab. (Parallel zu anderen Listenern, welche andere Queries abarbeiten).

Ein anderes Problem dass ich grad mit dem Test-Service sehe ich dass am 14.07. Wartungsarbeiten angekündigt wurden vom Hoster. Nun liegt der Service und die DB auf einem Server - somit wäre morgen der gesamte Hersteller nicht online. Ich müsste jetzt die DB und den Service wo anders hin zieehen wenn der morgen unbedingt laufen müsste. Aber da könnte man mit einer zentralen DB iwo anders Abhilfe schaffen was aber wiederum Netzwerklatenz mit sich bringt und andere Netzwerkprobs. Ich geh jetzt mal nicht davon aus, dass der Service da morgen 1 Tag weg ist, aber so ein Server kann ja auch mal abschmieren.


----------



## OnDemand (13. Jul 2020)

Glaub hier hab ich was gefunden um einen Listner programmatisch hinzufügen zu können. https://stackoverflow.com/questions...ogrammatically-subscribe-to-topics-on-the-fly


----------



## mrBrown (13. Jul 2020)

NicoDeluxe hat gesagt.:


> Eher die Anzahl der Zeilen, wenn ich mir den einen Hersteller anschaue, der hat 200k Artikel x 10 User (da jeder andere Preise, usw haben kann) dann dauern die Updates ewig oder?


Ewig ist relativ – es muss nur schnell genug gehen, und bei 10 Usern wären das 6min für 200k Artikel, das sollte in jedem Fall machbar sein.



NicoDeluxe hat gesagt.:


> Ein anderes Problem dass ich grad mit dem Test-Service sehe ich dass am 14.07. Wartungsarbeiten angekündigt wurden vom Hoster. Nun liegt der Service und die DB auf einem Server - somit wäre morgen der gesamte Hersteller nicht online. Ich müsste jetzt die DB und den Service wo anders hin zieehen wenn der morgen unbedingt laufen müsste. Aber da könnte man mit einer zentralen DB iwo anders Abhilfe schaffen was aber wiederum Netzwerklatenz mit sich bringt und andere Netzwerkprobs. Ich geh jetzt mal nicht davon aus, dass der Service da morgen 1 Tag weg ist, aber so ein Server kann ja auch mal abschmieren.



Jetzt stell dir zum Vergleich mal vor, der zentrale Datenbankserver wird gewartet. Statt einem einzelnen Service wären dann alle Services betroffen 

Und in dem Fall lässt sich das ja einfach über's Einspielen des Backups lösen, macht man im Idealfall sowieso öfters mal um's zu testen. Alten Server stoppen, Backup der DB machen, auf neuem Server starten und die Wartung kann dir egal sein


----------



## OnDemand (13. Jul 2020)

Joa da hast Recht, wenn man genug Vorlauf hat kann man ja entscheiden: 

1. Wartung ist nachts, dauert nur 4 Stunden > Kunden informieren gibt keine Updates in der Zeit erledigt
2. Wenn es was längeres ist kann man das ja umziehen. Vorausgesetzt man kommt an die Sicherung ran (wenn die Möhre abgeschmiert ist)


Wie bist du oben auf die 6 Minuten gekommen? Geschätzt? das wären dann 2mio Datensätze in der Tabelle bei 10 Nutzern.


----------



## mrBrown (13. Jul 2020)

NicoDeluxe hat gesagt.:


> Wie bist du oben auf die 6 Minuten gekommen?


Es soll doch stündlich laufen? Bei 10 Nutzern in einer Stunde macht das 6min pro Nutzer


----------



## OnDemand (13. Jul 2020)

Die laufen alle parallel.  Alle 10 beginnen um 10:00 zb nicht verteilt auf die Stunde oder steh ich grad auf dem Schlauch und verstehe dich falsch


----------



## mrBrown (13. Jul 2020)

NicoDeluxe hat gesagt.:


> Die laufen alle parallel. Alle 10 beginnen um 10:00 zb nicht verteilt auf die Stunde oder steh ich grad auf dem Schlauch und verstehe dich falsch


Na wie sie innerhalb dieser Stunde laufen kannst du ja beliebig festlegen.

Entweder alle hintereinander, dann im Schnitt 6min, oder alle gleichzeitig, dann müssen sie nur innerhalb einer Stunde fertig werden


----------



## OnDemand (13. Jul 2020)

Alle mit einem Mal ist der Plan. Wenn zu viele werden dann splitten wir das evtl auf in 10er Schritten oder so.

vielleicht könnte ich das alles noch reduzieren und das abspeichern, was überwacht werden soll. Daten wie EAN, MPN und solcher Nummern die ändern sich nie die brauch ich nur 1 x beim Anlegen.

Was hälst du von meiner Idee mit dem Query pro User? Ich sehe das wie eine Art Briefkasten der vollgestopft werden kann und wenn es einen Listener gibt arbeitet der das alles schön ab. Der Listener selbst sollte horizontal skalieren, also je Kunde ein Listener. Es muss nicht sein dass es pro User mehrere Listener gibt, der kann den Queue ruhig nach Prio/Fifo abarbeiten.

Hoffe das geht überhaupt. Hast du schon mal mit Sagas gearbeitet? Wäre das vielleicht auch noch eine Variante?


----------



## mrBrown (13. Jul 2020)

NicoDeluxe hat gesagt.:


> Was hälst du von meiner Idee mit dem Query pro User? Ich sehe das wie eine Art Briefkasten der vollgestopft werden kann und wenn es einen Listener gibt arbeitet der das alles schön ab. Der Listener selbst sollte horizontal skalieren, also je Kunde ein Listener. Es muss nicht sein dass es pro User mehrere Listener gibt, der kann den Queue ruhig nach Prio/Fifo abarbeiten.


Eine Query pro Nutzer würde ich vermutlich nutzen, Listener kann man allerdings unabhängig davon skalieren.



NicoDeluxe hat gesagt.:


> Hast du schon mal mit Sagas gearbeitet? Wäre das vielleicht auch noch eine Variante?


Wofür sollte das eine Variante sein?


----------



## OnDemand (13. Jul 2020)

mrBrown hat gesagt.:


> Wofür sollte das eine Variante sein?


Das man zb ein neues Produkt nimmt und mittels Saga über verschiedene Services schleift zb Import > speichern in tenant DB > export nach Kundenkassensystem oder was da auch immer hängt.

Ich bekomm das iwie nicht hin zur Laufzeit einen Listener auf einen neuen Query zu erstellen. Muss mir dass dann nochmal in Ruhe ansehen.


----------



## OnDemand (13. Jul 2020)

Nochmal mit den Queries, angenommen unser Programm geht durch die Decke und wir haben 1000 User. Ist das dann nicht zu viel mit den Queries 1000 - ist ein ActiveMQ und wie sie alle heißen dafür gemacht? Stell ich mir irgendwie schwer vor


----------



## mrBrown (13. Jul 2020)

NicoDeluxe hat gesagt.:


> Das man zb ein neues Produkt nimmt und mittels Saga über verschiedene Services schleift zb Import > speichern in tenant DB > export nach Kundenkassensystem oder was da auch immer hängt.


Saga legt da nur ein Transaktions-System drüber, das dürfte in deinem Fall Unsinn sein.



NicoDeluxe hat gesagt.:


> Nochmal mit den Queries, angenommen unser Programm geht durch die Decke und wir haben 1000 User. Ist das dann nicht zu viel mit den Queries 1000 - ist ein ActiveMQ und wie sie alle heißen dafür gemacht? Stell ich mir irgendwie schwer vor


Klar kommt ActiveMQ damit klar, da kann man relativ einfach horizontal und vertikal skalieren.


----------



## OnDemand (13. Jul 2020)

mrBrown hat gesagt.:


> Klar kommt ActiveMQ damit klar, da kann man relativ einfach horizontal und vertikal skalieren.


Cool danke, wollte mich nur nochmal absichern dass es nicht doch irgendwo ein Nadelöhr gibt


----------



## OnDemand (23. Jul 2020)

Ich bekomme es nicht hin, pro User einen Queue zu erstellen, ist auch vielleicht nicht so sinnvoll.

Ist es denn ratsam Daten in einer Message unter zu bringen? Am Beispiel Importservice hat ein neues Produkt festgestellt:
Variante A :
Message mit allen neuen Produkten in der Payload an den Broker senden, Listener holt ab und verarbeitet.
Problem: Payload zu groß!

Variante B :
Message senden "Hey neues Produkt Artikelnummer =123", Listener holt die Message und holt sich per REST das Produkt mit der SKU 123


----------

