Microservices StrukturPlanung

mrBrown

Super-Moderator
Mitarbeiter
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?

Lese ich da unterschwellig heraus, dass ich die DB auf dem selben Server installieren soll? :D
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

Top Contributor
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

Top Contributor
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

1591992462126.png
 

mrBrown

Super-Moderator
Mitarbeiter
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.

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

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

Top Contributor
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

Top Contributor
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 {
Code:
@EmbeddedId
private ProductId id;

...
}

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

OnDemand

Top Contributor
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?
 
Zuletzt bearbeitet:

mrBrown

Super-Moderator
Mitarbeiter
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.

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

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 :D
Mit H2 kann man auch Problemlos auf der Platte speichern. Die Datenbank nur im RAM halten ist nur eine der möglichen Optionen.
 

LimDul

Top Contributor
Ah ne h2 wird ja glaube gelöscht bei neustart. oook dann hab ich ein Problem :D
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

Top Contributor
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 ;)
 
Zuletzt bearbeitet:

mrBrown

Super-Moderator
Mitarbeiter
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

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

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

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

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.
 

mrBrown

Super-Moderator
Mitarbeiter
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.

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

mrBrown

Super-Moderator
Mitarbeiter
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

Top Contributor
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

Super-Moderator
Mitarbeiter

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

Top Contributor
oh man das ist ja nett, danke für deine Hilfe. Hast ein Bier gut bei mir :D 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.
 

OnDemand

Top Contributor
ne nich wirklich :D 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 :p)
 

OnDemand

Top Contributor
Halöööle :D

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

Top Contributor
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

Super-Moderator
Mitarbeiter
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.

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.

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

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

Top Contributor
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 :D
 

mrBrown

Super-Moderator
Mitarbeiter
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.

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.

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

Top Contributor
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

Super-Moderator
Mitarbeiter
Sehr grob und unübersichtlich, aber ich hoffe man versteht es:
Untitled Diagram.png

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.

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.

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.

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

Top Contributor
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

Super-Moderator
Mitarbeiter
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.

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.

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.

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

Top Contributor
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 :rolleyes:
 

OnDemand

Top Contributor
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

Top Contributor
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

Top Contributor
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

Super-Moderator
Mitarbeiter
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?

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.

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

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

mrBrown

Super-Moderator
Mitarbeiter
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.

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

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

OnDemand

Top Contributor
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 :D
 

mrBrown

Super-Moderator
Mitarbeiter
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 :D
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

Top Contributor
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

Super-Moderator
Mitarbeiter
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.

Hast du schon mal mit Sagas gearbeitet? Wäre das vielleicht auch noch eine Variante?
Wofür sollte das eine Variante sein?
 

OnDemand

Top Contributor
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.
 
Ähnliche Java Themen

Ähnliche Java Themen

Neue Themen


Oben