# Allgemeine Architekturfrage: REST API, Job Queue, Thread Pool unter Spring Kontrolle



## RoNa (20. Jun 2017)

Hallo zusammen,

ich denke, dass Unterforum ist das richtige. Wenn nicht, mögen das die lieben Admins verschieben ;-)

Ich habe folgende Anforderung an das zukünftige System:

Rest API für den Auftragsempfang
Die Aufträge sollen in einer Queue ( oder Deque ) geparkt werden
Danach sollen die Aufträge nach einem FIFO-Prinzip verarbeitet werden. 
Die Verarbeitung soll performant laufen. Am besten mit einem Threadpool.

Das ganze soll auf Tomcat 8 unter Java 8 laufen. Einsatz von Spring ist sehr wünschenswert. Die Rest-Endpoints habe ich schon mit Spring MVC gemacht. 

Hat jemand eine Idee, wie ich es am besten aufbauen soll? 

Hier noch ein Bild, das das Ganze visualisiert:

Hat jemand eine Idee?

Gruß,

Robert


----------



## Thallius (20. Jun 2017)

Tomcat -> Spring != Performant

SCNR

Claus


----------



## mrBrown (20. Jun 2017)

Hast du dir `@Async` schon mal angeguckt?


----------



## Tobse (20. Jun 2017)

Also nur eine in-memory Queue würde ich nicht nehmen; wenn der Server abschmiert, ist alles verloren, was noch nicht verarbeitet wurde. Du musst also zusätzlich noch eine Datenhaltung einführen, um die in-memory Queue wieder neu zu befüllen. Dann aber kommst du wieder in die Situation, dass du darauf achten musst, dass kein Auftrag doppelt ausgeführt wird in obskuren Konstellationen aus Serverausfall, zustand der in-memory Queue und der Datenhaltung.
Oder du sparst dir den Aufwand und nimmst eine Message-Queue. Apache Kafka könnte nützlich sein (wenn du hipp sein und Kafka verwenden willst), ist aber vmtl nicht die beste Wahl. Eine herkömmlicher Messaging-/Queueing-Server ist wahrscheinlich genau das richtige.


----------



## RoNa (21. Jun 2017)

Hallo,
danke sehr für die Antworten.



mrBrown hat gesagt.:


> Hast du dir @Async schon mal angeguckt?


Das habe ich schon mal überlegt. Habe ich auch ausprobiert, hat aber nicht so funktioniert. Vielleicht habe ich etwas falsch gemacht :-( Hast Du irgendwo ein Beispiel?



Tobse hat gesagt.:


> wenn der Server abschmiert, ist alles verloren, was noch nicht verarbeitet wurde



Ist schon klar. Das war genau bis jetzt das Problem (Das System gibt es bereits ) Als In-Memory Queue habe ich im Prototyp ConcurrentLinkedDeque genommen. Hier hoffe ich, dass _poll()_ den Job schnell genug aus der Queue entfernt.



Tobse hat gesagt.:


> Du musst also zusätzlich noch eine Datenhaltung einführen, um die in-memory Queue wieder neu zu befüllen



Genau. Ich habe hier an _*Redis*_ gedacht. Ist aber nicht schön, das als Job-Queue zu missbrauchen.



Tobse hat gesagt.:


> Dann aber kommst du wieder in die Situation, dass du darauf achten musst, dass kein Auftrag doppelt ausgeführt wird



Wäre nicht GANZ so schlimm.

Kafka kannte ich  noch gar nicht. Hat hier noh keiner benutzt. Da Wäre ich der 1. ;-)



Tobse hat gesagt.:


> Eine herkömmlicher Messaging-/Queueing-Server ist wahrscheinlich genau das richtige.



MQ ist mir aber zu schwergewichtig.

Andere Ideen?


----------



## Tobse (21. Jun 2017)

Ich hatte eben noch einen anderen Gedanken: das ganze muss ja ggf. skalieren; sprich du kannst ggf in die Situation kommen, dass mehrere Server Daten in die Queue schreiben; ob auch mehrere daraus lesen kann ich nicht beurteilen; aber die Möglichkeit würde ich auch in Betracht ziehen.

----
Also wenn du das Problem beheben sollst, dass keine Aufträge mehr verloren gehen, musst du die Daten auf jeden Fall dann persistieren, wenn du sie per REST entgegennimmst damit du per REST einen Fehler zurücksenden kannst, falls die Persistierung nicht geklappt hat (ist gleichbedeutend mit "der Server kann nicht garantieren, dass die Aufgabe abgearbeitet wird.").

Redis ist zwar eine Datenhaltung - wie man da eine saubere Queue hinbekommen kann, weiss ich allerdings nicht. Du könntest tatsächlich eine doppelt verkettete Liste im Redis aufbauen; ob das gut funktioniert musst du dann testen.

Apache Kafka ist eine Leichtgewichtige Message-Queue. Es hat einige Einschränkungen, was aber auch viel Performance und Flexibilität in manchen Anwendungsfällen mit sich bringt. Der Punkt bei Kafka ist, dass du Einträge aus der Queue nicht gezielt entfernen kannst. Sie werden entfernt wenn eine Gültigkeitsdauer überschritten ist oder wenn der Platz ausgeht; je nachdem, was du konfiguriert hast. Daher kannst du mit Kafka nicht richtig garantieren, dass ein Job aus der Queue auch ausgeführt wird, wenn er mal reingekommen ist (entweder weil zu viele Jobs reinkommen oder aber weil die Abarbeitung der vorhergehenden Jobs zu lange braucht).

Deshalb mein Tipp auf eine richtige Message Queue. Du kannst ggf. mit Redis eine nachbauen; aber warum sich den Aufwand geben, wenns das schon fertig gibt?


----------



## RoNa (21. Jun 2017)

Tobse hat gesagt.:


> mehrere Server Daten in die Queue schreiben


Das alte System wird seit 7 Jahren produktiv eingesetzt. Bis jetzt kamen wir immer mit 1 Server. Das Ganze ist auch nicht Unternehmens kritisch. Es sollte aber gehen.



Tobse hat gesagt.:


> dass du Einträge aus der Queue nicht gezielt entfernen kannst


Das ist schlecht!

Ich habe mal in einem Podcast gehört, dass der Hauptentwickler von Redis extra disque als Job Queue entwickelt hat. Vielleicht ist das was?


----------



## Tobse (21. Jun 2017)

So wie ich das verstehe ist disque auch in-memory. Und damit hast du das selbe Problem. Ich habe, ausser mit Kafka, noch mit keiner eingenständigen Message Queue gearbeitet, deshalb kann ich dir da nix empfehlen :/ aber diese Seite sieht ganz informativ aus: https://dzone.com/articles/exploring-message-brokers


----------



## Thallius (21. Jun 2017)

Klärt mal jemanden auf der davon so gar keine Ahnung hat. Was ist den jetzt so schwe z.b. Eine Sqlite DB zu nehmen und die ankommenden Aufträge dort reinzuschreiben? Dann sind sie sofort persistent und ich kann sie nach der Autoincrement ID abarbeiten. Wozu brauche ich bei sowas irgendwelche Kafka Frameworks oder sowas?


----------



## mrBrown (21. Jun 2017)

Thallius hat gesagt.:


> Klärt mal jemanden auf der davon so gar keine Ahnung hat. Was ist den jetzt so schwe z.b. Eine Sqlite DB zu nehmen und die ankommenden Aufträge dort reinzuschreiben? Dann sind sie sofort persistent und ich kann sie nach der Autoincrement ID abarbeiten. Wozu brauche ich bei sowas irgendwelche Kafka Frameworks oder sowas?





Tobse hat gesagt.:


> Also nur eine in-memory Queue würde ich nicht nehmen; wenn der Server abschmiert, ist alles verloren, was noch nicht verarbeitet wurde. Du musst also zusätzlich noch eine Datenhaltung einführen, um die in-memory Queue wieder neu zu befüllen. Dann aber kommst du wieder in die Situation, dass du darauf achten musst, dass kein Auftrag doppelt ausgeführt wird in obskuren Konstellationen aus Serverausfall, zustand der in-memory Queue und der Datenhaltung.


----------



## thecain (21. Jun 2017)

Die Lösung ist doch ganz "einfach" alle Angaben hier sprechen für eine Queue (z.b. RabbitMQ, HornetQ), was auch immer. Sooooooo schwergewichtig ist das auch nicht. Der Use-Case passt mMn perfekt


----------

