Learn Apache Flink - Performance Tuning
Episode 15 of 23

Learn Apache Flink - Performance Tuning

This episode optimizes Flink job performance: rearranging the job graph and operator chaining, tuning the checkpoint interval and state size, garbage collection tuning, and measuring throughput and end-to-end latency to verify every change.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Episode 14 managed resources; episode 15 optimizes how Flink works internally. Many jobs "run" but are wasteful: operators that could be merged are kept separate, checkpoints that are too frequent grind down throughput, or state balloons without limit. Tuning is the science of eliminating that waste.

We'll optimize the job graph and operator chaining, tune the checkpoint interval and state size, tune garbage collection, and close with how to measure throughput and end-to-end latency. Every practice in this episode follows one principle: measure first, change, then measure again.

Job Graph and Operator Chaining Optimization

Chaining Reduces Overhead

Flink merges adjacent stateless operators into one task to avoid serialization overhead between operators. The result: higher throughput, lower latency, and more efficient resources. Chaining happens automatically — and you can control it:

Control operator chaining
source
    .map(new ParseOrder()).startNewChain()
    .keyBy(Order::getUserId)
    .window(TumblingEventTimeWindows.of(Time.minutes(1)))
    .reduce(new SumOrder()).disableChaining()
    .sinkTo(sink);

startNewChain() forces the map operator to start a new chain, and disableChaining() separates reduce so it doesn't merge with the next operator. A rule of thumb: keep the default chaining, and separate only when you need isolation (for example, for different parallelism).

Reading the Job Graph

On the web dashboard, the job graph shows chaining as task blocks. The fewer blocks for the same workload, the more efficient. If you see many small separate operators that could be chained, consider simplifying the pipeline.

Checkpoint Interval and State Size

Setting the Interval Wisely

Checkpoints protect you from failure, but every checkpoint consumes resources. Too-frequent intervals reduce throughput; too-rare ones lengthen recovery time.

Checkpointing tuning
execution.checkpointing.interval: 2min
execution.checkpointing.min-pause: 30s
execution.checkpointing.tolerable-failed-checkpoints: 2
execution.checkpointing.unaligned.enabled: true

execution.checkpointing.unaligned.enabled allows checkpoints without waiting for barriers to spread — speeding up checkpoints on jobs with high backpressure, at the trade-off of larger state. Use it only if standard checkpoints are slow.

Limiting State Size with TTL

State that never expires is the most common waste. Give state a TTL:

State TTL to limit state size
import org.apache.flink.api.common.state.StateTtlConfig;
import org.apache.flink.api.common.time.Time;
 
StateTtlConfig ttlConfig = StateTtlConfig
    .newBuilder(Time.hours(24))
    .setUpdateType(StateTtlConfig.UpdateType.OnReadAndWrite)
    .cleanupInRocksdbCompactFilter(1000)
    .build();

cleanupInRocksdbCompactFilter cleans up expired state during RocksDB compaction — without it, TTL is only marked and not actually discarded until accessed. Slim state makes checkpoints lighter and GC happier.

Garbage Collection Tuning

Reducing GC Pauses

Jobs with many temporary objects trigger garbage collection that can spike latency. JVM options for the TaskManager are set in config.yaml:

GC options for the TaskManager
env.java.opts.taskmanager: -XX:+UseG1GC -Xms1g -Xmx1g
taskmanager.memory.managed.fraction: 0.4

env.java.opts.taskmanager injects JVM flags. G1GC is the modern default that splits the heap into regions and minimizes pauses. Reduce temporary allocations in code (for example, reusing objects in operators) because that has a bigger impact than any JVM flag.

Balancing Managed Memory

taskmanager.memory.managed.fraction partitions the heap for state. The larger it is for RocksDB, the smaller it is for objects and GC — find the balance by watching the heap usage and GC duration metrics on the dashboard.

Benchmarking Throughput and Latency

Measuring with DataGen

For benchmarks, use DataGen as the source so the load is controlled:

Run a benchmark job
./bin/flink run -d -p 4 target/bench-job.jar

Once running, read the metrics from the REST API:

Read throughput metrics
curl -s http://localhost:8081/jobs/overview

curl -s http://localhost:8081/jobs/overview gives the job list; from there the numRecordsOutPerSecond metric shows throughput, and the watermark latency metric shows end-to-end delay. Record the baseline before tuning and compare after every change.

End-to-end Latency

End-to-end latency is measured from the watermark metric: the gap between the latest event time and the current processing time shows how far the pipeline is behind. Latency that rises together with backpressure usually points to a specific operator — fix that operator rather than tuning globally.

The correct tuning flow
measure the baseline → change one variable → measure again → keep the better one

Conclusion

Episode 15 turned a running job into an efficient job: arranging the job graph with proper chaining, tuning the checkpoint interval and state TTL, tuning GC via JVM options, and benchmarking throughput and latency with measurable metrics.

The key takeaways:

  • Keep the default chaining; separate only when you need isolation.
  • The checkpoint interval balances throughput and recovery time.
  • State TTL with RocksDB cleanup prevents state from ballooning.
  • JVM flags help, but reducing allocations in code is more effective.
  • Measure the baseline, change one variable, then compare the results.

In the next episode, episode 16, we'll discuss savepoints, upgrades & migration — understanding the savepoint lifecycle and version compatibility, performing job upgrades and state migration, rollback strategies, and testing savepoint restores in staging. You'll learn to change production jobs without losing a single piece of state.

Learn Apache Flink - Performance Tuning | Learn Apache Flink