Mit Spring Batch 2.2.1, ich habe einen Spring Batch Job konfiguriert, habe ich diesen Ansatz verwendet:
Die Konfiguration ist die folgende:
Tasklet verwendet ThreadPoolTaskExecutor auf 15 Threads beschränkt
throttle-limit ist gleich der Anzahl der Threads
Chunk wird verwendet mit:
1 synchronisierter Adapter von JdbcCursorItemReader, damit er von vielen Threads gemäß der Spring-Batch-Dokumentationsempfehlung verwendet werden kann
Sie können den Aufruf von read () synchronisieren, und solange die Verarbeitung und das Schreiben der teuerste Teil des Chunks ist, kann Ihr Schritt noch viel schneller abgeschlossen werden als in einer Konfiguration mit einem einzigen Thread.
saveState ist false für JdbcCursorItemReader
Ein benutzerdefinierter ItemWriter basierend auf JPA. Beachten Sie, dass die Verarbeitung eines Elements in Bezug auf die Verarbeitungszeit variieren kann. Es kann einige Millisekunden bis wenige Sekunden dauern (& gt; 60s).
commit-interval auf 1 gesetzt (Ich weiß, es könnte besser sein, aber es ist nicht das Problem)
Alle jdbc-Pools sind in Bezug auf die Spring Batch doc-Empfehlung
Das Ausführen des Stapels führt aufgrund der folgenden Punkte zu sehr seltsamen und schlechten Ergebnissen:
Wenn Sie Spring Batch-Code betrachten, scheint die Ursache in diesem Paket zu liegen:
Ist diese Art zu arbeiten ein Feature oder ist es ein Limit / Bug?
Wenn es sich um ein Feature handelt, wie sieht die Konfiguration aus, um alle Threads zu erstellen, ohne durch lange Verarbeitungszeit ausgehungert zu werden, ohne alles neu schreiben zu müssen?
Beachten Sie, dass, wenn alle Elemente die gleiche Zeit benötigen, alles gut funktioniert und Multithreading in Ordnung ist. Wenn jedoch eine Elementverarbeitung viel länger dauert, ist Multithreading für die Zeit des langsamen Prozesses nahezu nutzlos.
Hinweis: Ich habe dieses Problem behoben:
Wie Alex gesagt hat, scheint dieses Verhalten ein Vertrag nach javadocs von:
zu seinUnterklassen müssen nur eine Methode bereitstellen, die das nächste Ergebnis * abruft und eine, die darauf wartet, dass alle Ergebnisse von gleichzeitig ablaufenden * Prozessen oder Threads
zurückgegeben werden
Schau dir an:
TaskExecutorRepeatTemplate # waitForResults
Eine andere Option für Sie wäre Partitionierung:
Michael Minella erklärt das in Kapitel 11 seines Buches Pro Spring Batch :
%Vor%
Partitionierer.java:
%Vor%
Hier ist, was ich denke, passiert:
Mit anderen Worten, für diesen Multi-Threading-Ansatz in Spring Batch hilfreich sein, muss jeder Thread in etwa der gleichen Zeit verarbeiten. In Anbetracht Ihres Szenarios, in dem die Verarbeitungszeit bestimmter Elemente sehr unterschiedlich ist, gibt es eine Einschränkung, bei der viele Ihrer Threads abgeschlossen sind und auf einem seit langem laufenden Geschwister-Thread gewartet wird, um auf den nächsten Verarbeitungsabschnitt zugreifen zu können.
Mein Vorschlag:
In meinem Fall, wenn ich das Drosselungslimit nicht setze, kommen nur 4 Threads in die read () -Methode von ItemReader, die auch die Standardanzahl von Threads ist, wenn sie nicht in tasklet-Tags gemäß der Spring-Batch-Dokumentation angegeben ist .
Wenn ich mehr Threads angeben möchte, z. B. 10 oder 20 oder 100, dann kommen nur 8 Threads in die read () - Methode von ItemReader
Das Limit von 8 aktiven Threads, unabhängig vom Wert von throttle-limit, wird möglicherweise durch Konflikte im Spring Batch-Job-Repository verursacht. Jedes Mal, wenn ein Chunk verarbeitet wird, werden einige Informationen in das Job-Repository geschrieben. Erhöhen Sie die Poolgröße, um die Anzahl der Threads zu berücksichtigen, die Sie benötigen!
Tags und Links java multithreading spring performance spring-batch