Tobias Flohre / Dennis Schulte | codecentric AG
Spring Batch – Performance und Skalierbarkeit
codecentric AG
Dennis Schulte
Düsseldorf
@denschu
www.github.com/denschu
blog.codecentric.de/author/dsc
codecentric AG
Tobias Flohre
Düsseldorf
@TobiasFlohre
www.github.com/tobiasflohre
blog.codecentric.de/en/author/tobias.flohre
codecentric AG
AGENDA
- Grundlagen Spring Batch
- Vier Aussagen zu Performance im Batch
- Skalierungsstrategien
codecentric AG
AGENDA
- Grundlagen Spring Batch
- Vier Aussagen zu Performance im Batch
- Skalierungsstrategien
codecentric AG
Traditionelles Batch-Pattern
Read Process Write
WAS IST EIN BATCH?
codecentric AG
SPRING BATCH
Automatisches Transaktionsmanagement
Skip
Retry
Persistente Job-Metadaten
Restart
Skalierungsfeatures
codecentric AG
DOMAIN / KONFIGURATION / ABLAUF
Item
ItemReader
ItemProcessor
StepJob
ItemWriter
Chunk
codecentric AG
- Job wird als Spring-Konfiguration erstellt
- Domain Specific Language manifestiert sich in XML-Namespace
- Zentrale Elemente- job
- step
- tasklet
- chunk
- reader- processor- writer- commit-interval
DOMAIN / KONFIGURATION / ABLAUF
13.04.2023 9
<job id="myJob" ><step id="myStep" > <tasklet> <chunk reader="myReader"
processor="myProcessor" writer="myWriter" commit-interval="1" />
</tasklet></step>
</job>
codecentric AG
- Reader, Processor und Writer implementieren bestimmte Interfaces- ItemReader<T>
- T read()- ItemProcessor<I,O>
- O process(I item)- ItemWriter<T>
- void write(List<? extends T> items)- Spring Batch bietet für sehr viele Use Cases Implementierungen an
- Lesen/Schreiben aus/in eine Datenbank
- Lesen/Schreiben aus/in ein Flat-File
- Lesen/Schreiben aus/in ein XML-File
- Lesen/Schreiben aus/in eine JMS-Queue
- Lesen/Schreiben mit JPA
- und viele mehr
DOMAIN / KONFIGURATION / ABLAUF
13.04.2023 10
codecentric AG
DOMAIN / KONFIGURATION / ABLAUF
13.04.2023 11
1Begin Step
Commit transactio
n
Finish Step
2
For each item
item == null ||
completionPolicy fulfilled
true
false
list of items
list of items
item == null
true
false
Open transactio
n
ItemReaderItem read()
ItemProcessorprocess(Item)
ItemWriterwrite(List<Item
>)
codecentric AG
*
*
*
*
DOMAIN / KONFIGURATION / ABLAUF
StepJob
JobInstance
JobExecution
StepExecution
JobParameters
Inkasso Kraftfahrt
Inkasso Kraftfahrt am 22.03.13
Inkasso Kraftfahrt am 22.03.13 erster Versuch
codecentric AG
- Infrastrukturkomponenten
DOMAIN / KONFIGURATION / ABLAUF
13.04.2023 13
JobRepository
JobLauncherPlatformTransaction
Manager
codecentric AG
AGENDA
- Grundlagen Spring Batch
- Vier Aussagen zu Performance im Batch
- Skalierungsstrategien
codecentric AG
VIER THESEN ZU PERFORMANCE IM BATCH
Kenne EVA
Aussage 1
Eingabe Verarbeitung Ausgabe
codecentric AG
VIER THESEN ZU PERFORMANCE IM BATCH
Aussage 1
<job id=“step-job"><step id=“xml-einlesen“>...</step><step
id=“xml-verarbeiten“>...</step><step id=“xml-schreiben“>...</step>
</job>
codecentric AG
VIER THESEN ZU PERFORMANCE IM BATCH
Aussage 1
<job id=“eva-job"><step id=“xml-step">
<tasklet><chunk reader=“xml-einlesen“
processor=“xml-verarbeiten" writer=“xml-schreiben“ />
</tasklet></step>
</job>
codecentric AG
VIER THESEN ZU PERFORMANCE IM BATCH
Aussage 1
- ExecutionContext ist kein Datenspeicher für Nutzdaten, sondern:- Zählerstände
- Steuerdaten
- Problem: HeapSize
- Processor und Writer sollten stateless sein- Parallelisierung
codecentric AG
VIER THESEN ZU PERFORMANCE IM BATCH
Kenne Deine nicht-funktionalen Anforderungen
Aussage 2
codecentric AG
VIER THESEN ZU PERFORMANCE IM BATCH
Aussage 2
- Mengengerüste
- Zu erreichender Durchsatz
- Was läuft parallel?
- Minimiere den Aufwand!
codecentric AG
VIER THESEN ZU PERFORMANCE IM BATCH
Kenne Deine Persistenzschicht
Aussage 3
codecentric AG
VIER THESEN ZU PERFORMANCE IM BATCH
Aussage 3
- Datenlokalität
- Art des DB-Zugriffs- JDBC
- ORM
- Transaktionsgröße (commit-interval)
codecentric AG
VIER THESEN ZU PERFORMANCE IM BATCH
Zahlen sind besser als Vermutungen
Aussage 4
codecentric AG
VIER THESEN ZU PERFORMANCE IM BATCH
Aussage 4
- Messen, Messen, Messen!- Wiederholbarkeit
- Immer nur einen Parameter ändern
- Immer im Blick: CPU, Speicher, Datenquellen
- Ergebnisse protokollieren
- Testdaten- Stetiger Verbesserungsprozess
- Randsysteme abdecken
- Tools verwenden- Profiling lokal
- Application Performance Management tools
codecentric AG
AGENDA
- Grundlagen Spring Batch
- Vier Aussagen zu Performance im Batch
- Skalierungsstrategien
codecentric AG
SKALIERUNGSSTRATEGIEN
- Multi-threaded Step
- AsyncItemProcessor -> AsyncItemWriter
- Parallel Steps
- Partitioning
- Remote Chunking
codecentric AG
SKALIERUNGSSTRATEGIEN
- Woher kommen die Threads?- java.util.concurrent.Executor
- ThreadPoolExecutor
<task:executor id="taskExecutor" pool-size="5"/>- ApplicationServer verwalten eigene Threadpools
codecentric AG
SKALIERUNGSSTRATEGIEN
- Multi-threaded Step
- AsyncItemProcessor -> AsyncItemWriter
- Parallel Steps
- Partitioning
- Remote Chunking
codecentric AG
MULTI-THREADED STEP
<job id="multithreadedStepJob">
<step id="step">
<tasklet task-executor="taskExecutor" throttle-limit="4">
<chunk reader="reader" processor="processor" writer="writer"
commit-interval="3" />
</tasklet>
</step>
</job>
<task:executor id="taskExecutor" pool-size="5"/>
codecentric AG
MULTI-THREADED STEP
13.04.2023 30
1Begin Step
Commit transactio
n
Finish Step
2
For each item
Open transactio
n
ItemProcessorprocess(Item)
ItemWriterwrite(List<Item
>)
ItemReaderItem read()
Threadsafe
File vs. DB vs. JMS
codecentric AG
+ Hoch skalierbar
+ Einfach zu konfigurieren
- Alle Komponenten müssen thread-safe sein
MULTI-THREADED STEP
codecentric AG
SKALIERUNGSSTRATEGIEN
- Multi-threaded Step
- AsyncItemProcessor -> AsyncItemWriter
- Parallel Steps
- Partitioning
- Remote Chunking
codecentric AG
ASYNCITEMPROCESSOR -> ASYNCITEMWRITER
Thread 1
Thread 3
Thread 2
process(item)
ItemReader
AsyncItemProcessor
AsyncItemWriter
process(item)
process(item)
codecentric AG
ASYNCITEMPROCESSOR -> ASYNCITEMWRITER
- AsyncItemProcessor and AsyncItemWriter
- Java Concurrency API- Future
- FutureTask
- Sehr einfach zu konfigurieren
- Optimal für aufwändige process-Schritte- Anreicherung von Daten über langsame APIs
- Komplexe Berechnungen
codecentric AG
ASYNCITEMPROCESSOR -> ASYNCITEMWRITER
<bean id="processor" class="org.sfw.batch.integration.async.AsyncItemProcessor">
<property name="delegate" ref="delegateProcessor"/>
<property name="taskExecutor" ref="taskExecutor"/>
</bean>
<bean id="writer" class="org.sfw.batch.integration.async.AsyncItemWriter">
<property name="delegate" ref="delegateWriter"/>
</bean>
<task:executor id="taskExecutor" pool-size="5"/>
- Achtung: commit-interval > 1
codecentric AG
SKALIERUNGSSTRATEGIEN
- Multi-threaded Step
- AsyncItemProcessor -> AsyncItemWriter
- Parallel Steps
- Partitioning
- Remote Chunking
codecentric AG
PARALLEL STEPS
Thread 2Thread 1
databaseJob
importTablePartner
loadTablePartner
importTableVertrag
loadTableVertrag
codecentric AG
PARALLEL STEPS
<job id="importJob">
<split id="splitStep" task-executor="taskExecutor">
<flow>
<step id="partnerStep">
<tasklet ref="partnerTasklet"/>
</step>
</flow>
<flow>
<step id="vertragStep">
<tasklet ref="vertragTasklet"/>
</step>
</flow>
</split>
</job>
codecentric AG
SKALIERUNGSSTRATEGIEN
- Multi-threaded Step
- AsyncItemProcessor -> AsyncItemWriter
- Parallel Steps
- Partitioning
- Remote Chunking
codecentric AG
PARTITIONING
Partitioner
Name … … Kategorie
Tobias … … A
Dennis … … A
Frank … … A
Daniel … … B
Ben … … B
Max … … B
Christian
… … C
Dirk … … C
Thomas … … C
codecentric AG
PARTITIONING
Partitioner
File 1
File 2
File 3
Name … … Kategorie
Tobias … … A
Dennis … … A
Frank … … A
Daniel … … B
Ben … … B
Max … … B
Christian
… … C
Dirk … … C
Thomas … … C
codecentric AG
PARTITIONING
Partitioner
File 1
File 2
File 3
Name … … Kategorie
Tobias … … A
Dennis … … A
Frank … … A
Daniel … … B
Ben … … B
Max … … B
Christian
… … C
Dirk … … C
Thomas … … C
codecentric AG
PARTITIONING
Partitioner
PartitionHandler
erzeugt Partitionen
verteilt Partitionen an Worker
Lokaler Prozess (TaskExecutor)
Spring Remoting
JMS
Hadoop YARN
codecentric AG
PARTITIONING
Finish Step
Begin Step
Commit transactio
n
For each item
false
Open transactio
n
ItemReaderItem read()
ItemProcessor
process(Item)ItemWriter
write(List<Item>)
Commit transactio
n
For each item
false
Open transactio
n
ItemReaderItem read()
ItemProcessor
process(Item)ItemWriter
write(List<Item>)
Commit transactio
n
For each item
false
Open transactio
n
ItemReaderItem read()
ItemProcessor
process(Item)ItemWriter
write(List<Item>)
Partitioner
codecentric AG
<job id="flatfilePartitioningJob">
<step id="partitionedStep" >
<partition step="flatfilePartitioningStep" partitioner="partitioner">
<handler task-executor="taskExecutor" />
</partition>
</step>
</job>
<bean id="partitioner" class="org.sfw...support.MultiResourcePartitioner">
<property name="resources" value="file:src/test/resources/*.csv" />
</bean>
PARTITIONING
codecentric AG
PARTITIONING
+ Hoch skalierbar
+ Kein Bottleneck beim ItemReader
+ Datenlokalität
- Struktur der Input Daten muss bekannt sein
codecentric AG
SKALIERUNGSSTRATEGIEN
- Multi-threaded Step
- AsyncItemProcessor -> AsyncItemWriter
- Parallel Steps
- Partitioning
- Remote Chunking
codecentric AG
REMOTE CHUNKING
Master Slave Node 1
Chunk Processor
Step 1
ItemReader
Ch
un
kPro
vid
er
ItemWriter
Slave Node 2
Chunk Processor
ItemWriter
codecentric AG
REMOTE CHUNKING
1Begin Step
Commit transactio
n
Finish Step
2
For each item
Open transactio
n
ItemReaderItem read()
ItemProcessor
process(Item)
ItemWriterwrite(List<Item>)
JMS
Commit transactio
n
JMS
Open transactio
n
codecentric AG
REMOTE CHUNKING
+ Hoch skalierbar
+ Struktur der Input Daten muss bekannt sein
- Ggf. Bottleneck beim ItemReader
- Transaktionale Middleware
- Alle Items werden serialisiert
codecentric AG
FRAGEN?
Dennis Schulte / Tobias Flohre
codecentric AGMerscheider Straße 142699 Solingen
www.codecentric.de
blog.codecentric.de
www.meettheexperts.de
13.04.2023 51