TS
Thomas Schmitz

Freiberuflicher IT-Berater, Softwareentwickler & DevOps. Praxisnahe Artikel zu API-Design, Architektur und Cloud-Workflows.

Serie: Spring Batch · Teil 4 von 12

Spring Batch Teil 4: Chunk Processing

Wie Reader, Processor und Writer zusammenspielen und warum die Chunk-Größe über Stabilität entscheidet.

Praxisnah Checkliste

Chunk Processing ist der Standardmodus in Spring Batch. Er klingt simpel, steckt aber voller Entscheidungen. Ein Chunk ist eine Gruppe von Items, die gemeinsam in einer Transaktion geschrieben werden. Transaktionsgrenzen, Speicherverbrauch, Restartability und Fehlerverhalten hängen direkt an der Chunk-Größe.

In diesem Teil bauen wir den ersten Chunk-orientierten Step und legen eine Entscheidungstabelle für die Chunk-Größe an. Reader und Writer kommen im nächsten Teil. Hier geht es um das Grundprinzip.

Zielbild

Nach diesem Kapitel kannst du einen Chunk-Step definieren, die Transaktionsgrenzen erklären und die Chunk-Größe bewusst statt nach Gefühl wählen.

Chunk Processing in einem Satz

Spring Batch liest Items, verarbeitet sie optional, sammelt sie zu einem Chunk und schreibt den Chunk in einer Transaktion.

Ablauf eines Chunks (Kurzfassung)

read -> process -> add to chunk -> write -> commit

Im Ablauf liefert der Reader Item für Item. Der Processor transformiert oder filtert jedes Item. Sobald der Chunk voll ist, ruft Spring Batch den Writer auf und die Transaktion wird committet. Bei Fehlern wird der aktuelle Chunk komplett zurückgerollt. Beispiel: Bei chunk(200) werden 200 Datensätze in einem Schritt geschrieben. Tritt beim Schreiben ein Fehler auf, sind alle 200 für diesen Chunk wieder weg.

Damit ist klar: Die Chunk-Größe ist auch die Commit-Granularität.

Chunk-Lifecycle als Zeitleiste

Ein Chunk ist eine Transaktion mit klaren Phasen. Das hilft beim Debugging und bei der Frage, wo ein Fehler eigentlich passiert:

  1. Lesen: Items werden nacheinander gelesen und optional verarbeitet.
  2. Sammeln: Der Step füllt den Chunk bis zur definierten Größe.
  3. Schreiben: Der Writer schreibt den kompletten Chunk.
  4. Commit: Die Transaktion wird abgeschlossen, der Fortschritt wird persistiert.

Fällt der Writer in Phase 3 aus, gibt es Rollback und der Chunk wird erneut verarbeitet (oder teilweise geskippt). Der Fortschritt bleibt immer auf dem letzten erfolgreichen Commit stehen. Genau deshalb ist die Chunk-Größe so zentral für Restartability.

Mini-Beispiel (7 Items, chunk(3))

Die Items verteilen sich auf drei Chunks: 3 + 3 + 1. Scheitert der zweite Chunk beim Schreiben, sind die ersten 3 Items sicher, die nächsten 3 werden erneut verarbeitet, das letzte wartet. Je größer der Chunk, desto größer sind also die Fehlerkosten.

Ein minimaler Chunk-Step

Ausschnitt: Bean-Methode in einer @Configuration-Klasse.

import org.springframework.batch.core.Step;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.infrastructure.item.ItemProcessor;
import org.springframework.batch.infrastructure.item.ItemReader;
import org.springframework.batch.infrastructure.item.ItemWriter;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.PlatformTransactionManager;

@Bean
public Step importStep(JobRepository jobRepository,
                       PlatformTransactionManager transactionManager,
                       ItemReader<RawRow> reader,
                       ItemProcessor<RawRow, Person> processor,
                       ItemWriter<Person> writer) {

    return new StepBuilder("importStep", jobRepository)
            .<RawRow, Person>chunk(200)
            .transactionManager(transactionManager)
            .reader(reader)
            .processor(processor)
            .writer(writer)
            .build();
}

Wichtig: ItemProcessor ist optional. Wenn er null zurückgibt, wird ein Item gefiltert und nicht geschrieben. Die chunk(200) definiert auch das Commit-Intervall. Fehler im Writer bedeuten ein Rollback des gesamten Chunks.

Chunk-Größe: Entscheidungstabelle

Chunk-Größe Vorteile Nachteile Typische Symptome
klein (10 bis 50) kurze Transaktionen, schneller Retry viel Overhead, mehr Commits hohe DB-Last, langsamer Durchsatz
mittel (100 bis 500) guter Kompromiss mittlere Latenz pro Chunk seltene, aber merkbare Rollbacks
groß (1000+) hoher Durchsatz hoher RAM, lange Rollbacks lange Laufzeiten bei Fehlern

Pragmatische Startwerte: Für CSV und DB sind 100 bis 300 ein guter Start. Danach erst messen und feinjustieren. Der erste Wert ist nie final.

Chunk-Größe beeinflusst mehr als Performance

Die Größe entscheidet nicht nur über Durchsatz. Sie bestimmt Recovery, Speicher und Nebenwirkungen wie aktive Locks in der DB.

Merke: Große Chunks sind nur dann sinnvoll, wenn deine I/O-Pipeline stabil ist.

Chunk-Größe und Fehlerkosten

Rollback bedeutet: Alle Items im aktuellen Chunk werden erneut verarbeitet. Der Aufwand pro Fehler wächst also linear mit der Chunk-Größe. Beispiel: Bei chunk(500) kostet ein einziger Fehler im Writer das Neuverarbeiten von 500 Items. Bei chunk(50) sind es nur 50.

Wenn Fehler häufig sind (z. B. Datenqualität schwankt), sind kleinere Chunks oft robuster, selbst wenn der Durchsatz sinkt.

Chunk-Größe, Locks und Speicher

Bei DB-Writes hält die Transaktion Locks bis zum Commit. Große Chunks verlängern die Lock-Zeit und können andere Prozesse blockieren. Gleichzeitig liegen alle Items eines Chunks im Speicher. Wenn jedes Item groß ist (viele Felder, große Strings), kann ein zu großer Chunk schnell zu Speicherproblemen führen. Deshalb gilt: Je größer die Item-Objekte, desto kleiner der Chunk.

Fehlerverhalten im Chunk-Modus

Ein Fehler im Reader, Processor oder Writer bricht den aktuellen Chunk ab. Je nach Konfiguration liest Spring Batch den Chunk erneut, überspringt Items (Skip) oder verarbeitet sie erneut (Retry). Das behandeln wir ausführlich in Teil 7: Fehlerbehandlung & Validierung. Wichtig ist: Rollback betrifft den gesamten Chunk. Reader müssen restartable sein, sonst drohen Duplikate. Writer müssen idempotent sein, sonst entstehen doppelte Writes.

Artefakt: Chunk-Entscheidungs-Checkliste

  • [ ] Wie teuer ist ein Fehler? (Rollback-Kosten pro Chunk)
  • [ ] Wie groß sind die Items im Speicher?
  • [ ] Wie stabil ist die Quelle (Datenqualität, I/O)?
  • [ ] Wie lang dürfen DB-Locks maximal sein?
  • [ ] Wie schnell muss ein Re-Run starten können?

Anti-Patterns

Chunk-Größe nach Gefühl führt zu instabilen Laufzeiten und Debugging. Sehr große Chunks mit instabilen Quellen kosten bei jedem Fehler Minuten. Reader ohne State macht Restartability praktisch unmöglich. Processor mit Seiteneffekten wirkt bei Retries doppelt.

Kurzfazit

Chunk Processing ist der Default und definiert deine Transaktionsgrenzen. Die Chunk-Größe ist eine betriebliche Entscheidung, keine Kleinigkeit. Im nächsten Teil bauen wir Reader und Writer für CSV und H2 konkret auf.

Alle Teile der Serie: Serie: Spring Batch

Mehr Beiträge aus dem Blog.