Hoher Sys-Load bei Multithreaded Anwendung

alderwaran

Mitglied
Ich bin grade dabei eine Java-Anwendung zu schreiben die mehrere (hier
24) Threads startet um Dokumente mit Apache FOP zu erzeugen.

Das grobe Gerüst ist:
Ein Thread hat eine Liste (ArrayList oder Vector, beides probiert), und
stellt eine synchronized Methode getNextDocument() bereit.
Die (24) Generatorenthreads rufen getNextDocument() in einer loop in
ihrer jeweiligen run() Methode, sind bei der Bearbeitung des Datenpakets
350-500ms beschäftigt, updaten dabei Datenfelder im Objekt das mit
getNextDocument() geliefert wurde, und wenn sie fertig sind rufen sie
wieder getNextDocument() bis der Aufruf null zurück gibt.
Während dieser Zeit gibt es keine Netzwerk- oder Dateisystemzugriffe -
das Programm hat alle Daten im RAM und verarbeitet sie.

Jetzt stößt mir ein wenig bitter auf, dass die Prozesse so viel Sys-Load
machen. User-Load wäre so weit ich das verstanden habe ok - dann macht
das Programm was, aber Sys-Load bedeutet doch Kontext-Switches,
Speicherallokierung, oder anders gesagt: Zeit die der Kernel braucht,
und die dem Programm nicht zur Verfügung steht.
Dazu kommt das ich mich nicht erinnern kann den gleichen Sys-Load im POC
Progrämmchen zu haben - das auch schneller mehr Dokumente erzeugte.
Irgendwie irgendwo hat sich beim schreiben des eigentlichen Programms
ein Fehler eingeschlichen, der mir ordentlich Performace klaut… nur… wo?

Anbei Bildchen:
1. htop Anzeige der Prozessorbelastung. Grün ist OK, User-Land, rot ist
böse.
htop.png

2. dstat zeigt htop kumuliert. Auffällig sind die vielen Interrupts.
dstat.png

3. irqstats. Hier gehen bei der Generierung die "Local Timer
Interrupts", und die "TLB Shootdowns" hoch. Liegt hier das Problem? Wenn
ja, welcher Teil von Java macht sowas? Analysemöglichkeit? Lösung?
irqstats-day.png

4. VisualVM Trace während des Programmablaufs (RAM Rampe am Anfang ist
"Daten holen", der Rest ist "Generierung" mit den beschriebenen
Symptomen). Auffällig hier: Es kann nicht am GC liegen, der dümpelt nur
so vor sich hin.
VisualVM.jpg

Kann mir da jemand weiter helfen? Schon mal ähnliche Probleme gehabt?
 

Thallius

Top Contributor
Was passiert denn wenn du das Ganze einfach mal auf 1 Thread begrenzt? Überhaupt glaube ich nicht, dass parallelisierung hier einen großen Geschwindigkeitsvorteil liefern wird. Deshalb probier es doch erstmal mit einem, dann mit zwei und dann schau wieviele Dir noch einen Gewinn im Speed bringen.

Gruß

Claus
 

alderwaran

Mitglied
Was passiert denn wenn du das Ganze einfach mal auf 1 Thread begrenzt? Überhaupt glaube ich nicht, dass parallelisierung hier einen großen Geschwindigkeitsvorteil liefern wird. Deshalb probier es doch erstmal mit einem, dann mit zwei und dann schau wieviele Dir noch einen Gewinn im Speed bringen.

Im POC bei einem Thread 5 Dokumente/s, bei 24 100 Dokumente/s. Weniger Threads brachten weniger Dokumente, mehr Threads (bis 32) stagnation bis hin zu weniger. 24 Threads war der Sweet-Spot.

Aber so etwas gibt es doch schon in der Java API. java.util.concurrent.BlockingQueue
Was passiert, wenn du das verwendest und keine manuelle Synchronisierung durchführst?

Die Klasse welche die Daten über "synchronized getNextDocument()" zurück liefert beinhaltet noch Datenbank-connektivität zum Daten holen vor dem Generierungslauf, und liefert außerdem noch Statistikdaten für einen ggf angeschlossenen (Grafischen) Client - die Verwaltungsoberfläche.
Ich hann Timinginformationen aus jedem Generatorthread loggen wie lange auf ein getDocument() gewartet werden muss, erwarte mir aber nicht viel davon, weil es sich im endeffekt nur um ein "return documentList.get(counter)" handelt, zusammen mit einem hochzählen des Document-counters.
Desweiteren wird BlockingQueue es im endeffekt nicht anders machen: eine synchronized get() Methode.

Um hier nochmal auf das POC zurück zu kommen: Bei der ersten implementierung war es sogar so, dass die Dokumenten-liefernde Klasse die Daten aus der Datenbank holte, und gleichzeitig bereits begonnen wurde Dokumente zu generieren - es wurde also eine ArrayList mit Objekten gefüllt, und gleichzeitig wurden über getDocument() Objektreferenzen an Dokumentgeneratoren geliefert. Das geht aus organisatorischen Gründen nun nicht mehr, sollte für die neue Implementierung aber auch keinen Performancenachteil darstellen.

Die Frage bleibt: Was macht bei Java eigentlich einen hohen Sys-Load? Der GC wirds hier nicht sein.
 

DrZoidberg

Top Contributor
Ich würde erstmal versuchen ein minimales lauffähiges Beispiel zu erstellen und das dann hier posten. Andernfalls können wir nur raten.
 

alderwaran

Mitglied
Ich würde erstmal versuchen ein minimales lauffähiges Beispiel zu erstellen und das dann hier posten. Andernfalls können wir nur raten.
ich finde es wenig sinnvoll ein komplettes programm mit einigen eingebauten frameworks auf "hello world"-status eindampfen zu wollen.

egal, ich habs.
das problem war, dass das test-XSLT einen font benutzen will, der nicht
im standard-repertoire von PDF definiert ist, und FOP in seiner
config-datei so konfiguriert war, dass er bei unbekannten Fonts das
Betriebssystem nach passenden font-files durchsucht.
resultat war, dass die generatorenthreads ein paar 100ms damit
beschäftigt waren, verzeichnisstrukturen abzugrasen (siehe bild).netbeans-profiler.png
 

Thallius

Top Contributor
Das hätte aber bei einem einzigen Thread dann auch auftreten müssen und da hättest du dann hellhörig werden müssen das es. Überhaupt nichts mit dem multithreadding zu tun hat
 

alderwaran

Mitglied
Das hätte aber bei einem einzigen Thread dann auch auftreten müssen und da hättest du dann hellhörig werden müssen das es. Überhaupt nichts mit dem multithreadding zu tun hat

ist ja auch bei nur einem aufgetreten, das problem ist dabei nur, das ein einzelner thread so fix zwischen den CPU-kernen springt, dass man es da schlecht sehen kann.
aber wenn du schon mal da bist: was könnte der grund sein, das apaches DirectoryWalker so lange braucht um ein Verzeichnis zu lesen, obwohl kein disk-io stattfindet weil die verzeichnisstruktur wohl schon längst im inode-cache ist?
 

Thallius

Top Contributor
Ka. Das ist genau der Grund warum ich solche Frameworks nach Möglichkeit vermeide wenn ich es mit vertretbarem Aufwand selber machen kann. Ist zwar schön zeitsparend sowas fertiges zu nehmen aber wenn es halt nicht zu 100% genauso arbeitet wie man will, dann verbringt man mehr Zeit mit dem debuggen als wenn man es gleich selber geschrieben hätte
 

Ähnliche Java Themen

Neue Themen


Oben