Performance ist selten ein einzelner Parameter. In Batch-Jobs ist sie das Ergebnis aus Chunk-Größe, I/O (Ein-/Ausgabe), Datenbank-Konfiguration, CPU und Speicher. Wer blind optimiert, verschiebt das Problem nur. Wer misst, findet die echten Engpässe. Für Einsteiger heißt das: Erst messen, dann drehen.
In diesem Teil geht es um die Grundlagen: Welche Stellschrauben es gibt, wie du sie sinnvoll kombinierst und welche Messpunkte du brauchst, um das Ergebnis zu beurteilen.
Zielbild
Nach diesem Kapitel kannst du die wichtigsten Performance-Hebel benennen, Engpässe anhand von Metriken erkennen und Optimierungen kontrolliert und nachvollziehbar durchführen.
Mess-Setup: Baseline statt Bauchgefühl
Performance ist nur vergleichbar, wenn Input und Umgebung konstant sind. Baue dir ein fixes Testset (z. B. 100k Zeilen), starte den Job zweimal hintereinander (Warm-up) und miss erst den dritten Lauf. So vermeidest du Effekte durch Caches, JIT oder leere Buffers.
Mindestens messen solltest du:
- Step Duration (Laufzeit pro Step)
- Read/Write Count (Items)
- Commit Count (Anzahl Commits)
Eine einfache Kennzahl ist der Durchsatz:
throughput = writeCount / stepDuration (Items pro Sekunde)
Damit bekommst du eine stabile Vergleichsbasis für alle Optimierungen.
Die Performance-Hebel (Kurzliste)
Die wichtigsten Hebel sind Chunk-Größe als Commit-Intervall, Reader Fetch-Size (wie viele Zeilen die DB pro Abruf liefert), Writer Batch-Size (wie viele Inserts in einem Batch gehen), Datenbank-Indizes, Netzwerk/IO-Throughput (Durchsatz) sowie Threading/Parallelisierung später in der Serie.
Chunk-Größe: der größte Hebel
Die Chunk-Größe beeinflusst Commit-Overhead, Rollback-Kosten und RAM-Verbrauch. Zu kleine Chunks erzeugen viele Commits, zu große verursachen großen Verlust bei Fehlern und Speicherprobleme.
Ein typischer Startwert für CSV nach DB liegt bei 100 bis 300 Items pro Chunk.
Beispiel: chunk(200) bedeutet 200 Datensätze pro Commit.
Dann messen und anpassen. Keine Magie, nur Fakten.
Experiment-Design: nur einen Regler drehen
Ändere immer nur einen Parameter pro Testlauf. Sonst weißt du nicht, welcher Effekt von welcher Änderung kommt. Ein simples Raster hilft:
| Lauf | Chunk | Fetch-Size | Batch-Size | Ergebnis |
|---|---|---|---|---|
| A | 100 | 100 | 100 | baseline |
| B | 200 | 100 | 100 | ? |
| C | 200 | 200 | 100 | ? |
| D | 200 | 200 | 200 | ? |
So siehst du, ob der Engpass in der DB, im Reader oder im Writer liegt.
Reader Fetch-Size
Bei DB-Readern kannst du steuern, wie viele Datensätze auf einmal vom Server geladen werden. Zu klein = viele Roundtrips, zu groß = Speicherlast. Beispiel: Fetch-Size 200 holt 200 Zeilen pro Datenbankabruf.
Heuristik: Starte mit Fetch-Size = Chunk-Größe. Wenn Netzwerk-Latenz der Engpass ist, erhöhe schrittweise bis maximal 5× Chunk-Größe. Bei sehr großen Datensätzen (viele Spalten, LOBs) bleib beim 1:1-Verhältnis, um Speicherprobleme zu vermeiden. Miss den Effekt über die Step-Dauer.
Writer Batch-Size
Der Writer schreibt typischerweise in Batches. Batch-Size sollte der Chunk-Größe entsprechen, sonst sind Splits nötig. Zu große Batches können DB-Locks verstärken. Beispiel: Chunk 200, Batch-Size 200 = ein SQL-Batch pro Chunk.
In der Praxis sind 100 bis 300 Inserts pro Batch oft stabil, aber datenbank- und schemaabhängig.
Connection-Pool und Transaktionen
Parallelisierung und größere Chunks erhöhen den Bedarf an DB-Connections. Wenn der Pool zu klein ist, wartest du, statt schneller zu werden. Faustregel: Pool-Größe ≥ gleichzeitige Writer-Threads.
Auch die Transaktionsdauer zählt: große Chunks halten Locks länger und können andere Prozesse ausbremsen. Performance ist daher immer ein Zusammenspiel aus Chunk-Größe, Pool-Größe und Lock-Zeit.
Datenbank-Indizes: Fluch und Segen
Indizes beschleunigen Reads, aber verlangsamen Writes. Beispiel: Ein Index
auf email macht Suchen schneller, bremst aber Mass-Imports.
Empfehlung: Essenzielle Unique-Constraints bleiben aktiv. Nichtkritische Indizes kannst du bei Mass-Imports temporär deaktivieren, aber nur wenn das Business es erlaubt.
Metriken, die du immer brauchst
Du brauchst mindestens Read Count, Write Count, Commit Count, Skip Count und Step Duration. Diese Zahlen erklären fast alle Performance-Probleme. Ohne sie optimierst du blind. Beispiel: Hoher Commit Count zeigt oft zu kleine Chunks.
Metriken lesen lernen
Ein paar typische Muster:
- Read Count >> Write Count: Filterung im Processor oder Skips.
- Commit Count sehr hoch: Chunk-Größe zu klein oder viele Rollbacks.
- Step Duration steigt, Counts bleiben gleich: I/O oder DB-Latenz wächst.
Diese Muster helfen dir, den Engpass einzugrenzen, bevor du Parameter drehst.
Engpass-Matrix (CPU, I/O, DB)
Ein schneller Check:
- CPU hoch, DB-Last niedrig → Processor ist der Engpass.
- DB-Last hoch, CPU niedrig → DB/IO ist der Engpass.
- Beides niedrig, Laufzeit hoch → Netzwerk/Latenz oder Locks.
Das ist kein Beweis, aber eine Richtung für die nächste Messung.
Engpass-Diagnose (Mini-Checkliste)
Ein hoher Commit Count spricht für zu kleine Chunk-Größe. Lange Step-Dauer deutet auf I/O oder DB-Bottleneck hin. Hohe Skip Count ist ein Validierungs- oder Datenproblem, kein Performance-Thema. Steigende Laufzeit pro Run bedeutet oft wachsendes Datenvolumen oder steigende Indexlast.
Anti-Patterns
Chunk-Größe hochdrehen ohne Messung löst selten das Grundproblem. Indizes pauschal löschen kann Datenqualität brechen. Keine Metriken lassen Performance zur Gefühlssache werden. Optimierung ohne Testdaten liefert nicht reproduzierbare Ergebnisse.
Kurzfazit
Performance ist messbar und sollte auf Metriken basieren. Chunk-Größe, Fetch-Size und Batch-Size sind die ersten Stellschrauben. Ohne Messpunkte ist jede Optimierung riskant.
Im nächsten Teil geht es um Parallelisierung: Multi-threaded Steps, TaskExecutor und warum Thread-Safety eine Voraussetzung ist, keine Option.
Alle Teile der Serie: Serie: Spring Batch