Chris Collins

Tools · infra

Flink, simulated

An animated Flink job in your browser: Kafka partitions feeding chained operators, keyBy through key groups, event-time windows driven by watermarks, keyed state on HashMap or RocksDB, checkpoint barriers (aligned and unaligned), failure and recovery, a two-phase-commit Kafka sink, backpressure and rescaling from a savepoint — with guided scenarios, a key-group calculator and a window explorer.

Added

How to use it

A Flink streaming job in miniature that runs entirely in this page: a Kafka topic, a source, keyBy, a window (or a keyed process function) and a sink, deployed as parallel subtasks on TaskManager slots under a JobManager. Every record, watermark, checkpoint barrier, credit, acknowledgement and commit is a labelled packet on the diagram, and the rules — which window a record belongs to and when it fires, which subtask owns a key, when a barrier blocks a channel, what is restored after a failure and what a read_committed consumer sees — follow Flink’s own. Nothing here talks to a real cluster.

How to use it

Pick a scenario and press Start. Each step does something — changes the job, pauses a partition, kills a TaskManager, takes a savepoint — then plays until what the narration describes has happened and pauses so you can read. Next step moves on, Back rewinds (the simulator is deterministic, so it replays the earlier steps), ⏭ jumps to the end of the step and Step ⇥ advances to the next single thing that happens. Space plays and pauses; → is the next step. Every step links to the Flink documentation or paper that explains it. The Playground scenario has no script: build a pipeline under Pipeline and cluster settings and feed it events.

Speed and Hop time set the pace. At 1× the simulated clock runs in real time. Hop time is how long checkpoint traffic (triggers, barriers, acknowledgements, notifications, commits) and failure messages take to cross the diagram at 1×; while one is on its way the clock slows. The steady flow of records and watermarks is never slowed. Sim clock turns the slowing off. Hop time changes only how the run is shown, never what happens.

⛶ Full screen (or F) gives the diagram the whole window; Esc leaves. In full screen the stats, watermarks, output, checkpoints and event log sit in a side panel that ▤ Panels (or [) shows and hides; on a phone the panel opens under the diagram.

  • The diagram. The JobManager at the top (job status, the CheckpointCoordinator’s current or last checkpoint, attempts and restarts); the Kafka topic on the left with each partition’s end offset, read offset and lag (⏸ when watermark alignment paused it); one box per subtask, column by column (source → window or process → sink; chained operators share one box); the sink’s output on the right; and the TaskManagers with their slots at the bottom. A subtask shows its watermark, a busy / backpressured / idle bar (ms per second, as the web UI reports them), what it reads or which key groups it owns and how many keys and windows it holds, and one gauge per input channel — its buffers filling up (red when out of credit), ⏸ while blocked by checkpoint alignment, ↯ while its in-flight data is being persisted for an unaligned checkpoint. Records travel the channels coloured by key (labelled key@event time when traffic is light), watermarks as W, barriers as a black bar labelled CP n, credits as small green dots going back, and the JobManager’s triggers, acknowledgements, notifications and restores in violet. Tap anything to inspect it and act on it.

  • Stats. Job status, records read, windows fired, results visible to the consumer, uncommitted results, duplicates, late records dropped or sent to the side output, expired state, checkpoints, the last checkpoint’s duration and alignment (or persisted in-flight records), restarts and the highest backpressure.

  • Watermarks. For every subtask, the last watermark of each input (split or channel) and the resulting minimum.

  • Output. What a consumer sees (with read_committed, only committed transactions), the whole topic log (open, pre-committed, aborted records too), and the late side output.

  • Checkpoints. Recent checkpoints and savepoints: trigger time, duration, size (incremental and full for RocksDB), alignment time or persisted in-flight records, and the Kafka offsets stored.

  • Keyed state. Each window subtask’s key-group range and its state: windows per key with their aggregate (✓ when fired), or the ValueState counter with its age and TTL.

  • Kafka partitions. End offset, read offset, lag and which source subtask reads each partition.

  • Do something. Send an event with any key, partition and event time (now, out of order, late); pause or resume a partition; trigger a checkpoint; stop with a savepoint; rescale; kill a TaskManager; switch to unaligned checkpoints, idleness or a read_uncommitted consumer.

  • Settings rebuild the job: window type, size, slide, gap, allowed lateness, side output, aggregate, a filter, time characteristic, watermark bound, idleness, alignment, parallelism of each operator, max parallelism, slots, chaining, state backend, TTL, checkpoint interval and mode, sink, consumer isolation, the topic’s partitions, rate, keys, disorder and late records, and per-record costs. Each shows Flink’s default.

The other tabs: Key groups computes, for any keys, Java’s hashCode(), MathUtils.murmurHash, the key group and the owning subtask at two parallelisms (which keys move on rescaling), the key-group ranges, and the default max parallelism. The Window explorer takes events (key and event time) in arrival order and shows which tumbling, sliding or session windows they fall into, when each fires for a given out-of-orderness bound, late firings within the allowed lateness and the records dropped as late.

What it models

  • Kafka source (FLIP-27, Kafka connector): partitions are splits assigned to readers as KafkaSourceEnumerator.getSplitOwner does — ((topic.hashCode() × 31) & 0x7FFFFFFF) % readers, then round-robin; per-split watermarks; offsets in checkpoints, committed back to Kafka only for monitoring; earliest or latest starting offsets for new jobs.

  • Watermarks (generating watermarks): forBoundedOutOfOrderness (max timestamp − bound − 1 ms) emitted every pipeline.auto-watermark-interval (200 ms); a reader’s watermark is the minimum over its active splits; withIdleness marks quiet splits idle and sends WatermarkStatus.IDLE; an operator’s watermark is the minimum over its non-idle input channels; watermark alignment (FLIP-182) pauses splits ahead of the group’s slowest by more than the allowed drift.

  • Windows (windows): tumbling and sliding assigners with TimeWindow.getWindowStartWithOffset, session windows merged with TimeWindow.mergeWindows (touching windows merge), EventTimeTrigger (fire when the watermark reaches end − 1 ms; fire at once for a late element of a live window), cleanup at end − 1 + allowed lateness, numLateRecordsDropped and sideOutputLateData; processing-time windows on the clock. The window model follows Akidau et al., The Dataflow Model (VLDB 2015).

  • Keyed state and key groups: KeyGroupRangeAssignment — key group = MathUtils.murmurHash(key.hashCode()) % maxParallelism, owner = key group × parallelism / max parallelism, contiguous ranges [⌈i·M/p⌉, ⌊((i+1)·M − 1)/p⌋], default max parallelism min(max(nextPowerOfTwo(p + p/2), 128), 32768) — checked against Flink 1.20’s own classes. ValueState with TTL (OnCreateAndWrite, NeverReturnExpired, cleanup in full snapshots). State backends (docs): HashMap (objects on the heap) and RocksDB (serialized, slower access, incremental checkpoints).

  • Network stack: credit-based flow control — a channel gets buffers-per-channel exclusive buffers plus a share of floating-buffers-per-gate; a sender sends only with credit; full output buffers block the producing task, which is how backpressure propagates back to the sources and into Kafka lag (network stack deep-dive, back pressure).

  • Checkpoints: asynchronous barrier snapshots (Carbone et al., Lightweight Asynchronous Snapshots for Distributed Dataflows, 2015), a variant of Chandy and Lamport’s distributed snapshots (1985): the coordinator triggers the sources, which snapshot their offsets and inject barriers; aligned barriers block a channel until all inputs' barriers arrive; unaligned barriers (FLIP-76) overtake buffered data, which is persisted as channel state; tasks acknowledge after the asynchronous upload; the coordinator completes the checkpoint and notifies every task.

  • Recovery: a lost TaskManager is detected after the heartbeat timeout; the whole pipelined region restarts after the restart delay; state, Kafka offsets and (for unaligned checkpoints) in-flight data are restored from the last completed checkpoint. A plain sink then writes replayed results again; the exactly-once KafkaSink (two-phase commit: pre-commit on the barrier, commit on notifyCheckpointComplete, commit-or-abort on recovery) never exposes them to read_committed consumers.

  • Savepoints and rescaling: stop with a savepoint, restart with another parallelism; key groups are redistributed in contiguous ranges; a parallelism above the max parallelism is refused.

Limits

  • One pipeline shape: Kafka source (with an optional filter) → keyBy → one window or keyed process function → sink. No joins, CEP, SQL, broadcast state, iterations or async I/O operators (the backpressure scenario models async I/O as a lower per-record cost).

  • Records are individual events at modest rates; costs are fixed per record; buffers hold a fixed number of records; the network has a fixed latency; checkpoint uploads have a fixed speed.

  • Timeouts are much shorter than Flink’s defaults (heartbeat 50 s, restart delay 1 s, checkpoint timeout 10 min — each setting shows the default). No high availability, no region failover for disconnected graphs, no checkpoint storage, no changelog state backend, no buffer debloating.

  • Duplicates are judged by result identity (key, window, firing). A new job started by a scenario step writes to a fresh view of the output.

Linking to an example

Links can be written by hand. Add a tab after #: sim (the default), keygroups or windows. A link’s settings replace this page’s saved settings (a button restores yours).

Parameter Meaning Example

example

A scenario (list below), with its own settings; parameters given with it override the scenario’s

example=watermarks

scenario

The same, without the scenario’s own settings being written into the link

scenario=windows

partitions

Kafka partitions, 1–6

partitions=3

rate

Records per second per partition

rate=6

keys

Distinct keys, 1–8

keys=6

ooo

Records are out of order by up to this many ms

ooo=3000

lateEvery

Every n-th record is late (0: none)

lateEvery=5

lateBy

How late, in ms

lateBy=8000

srcPar

Source parallelism, 1–4

srcPar=2

winPar

Window / process parallelism, 1–4

winPar=3

sinkPar

Sink parallelism, 1–4

sinkPar=1

maxPar

Max parallelism (number of key groups)

maxPar=256

chain

Chain operators where possible

chain=false

time

event or processing

time=processing

window

tumbling, sliding, session or none (a keyed counter)

window=session

size

Window size in ms

size=10000

slide

Slide in ms (sliding windows)

slide=2000

gap

Session gap in ms

gap=3000

lateness

Allowed lateness in ms

lateness=5000

sideOutput

Send late records to a side output

sideOutput=true

bound

Watermark out-of-orderness bound in ms

bound=1000

idleness

withIdleness in ms (0: off)

idleness=3000

alignDrift

Watermark alignment max drift in ms (0: off)

alignDrift=2000

backend

hashmap or rocksdb

backend=rocksdb

ttl

State TTL in ms (keyed counter only; 0: off)

ttl=4000

ckInterval

Checkpoint interval in ms (0: off)

ckInterval=2000

ckMode

aligned or unaligned

ckMode=unaligned

sink

print, kafka (at-least-once) or kafka-eos (exactly-once)

sink=kafka-eos

isolation

The consumer’s read_committed or read_uncommitted

isolation=read_uncommitted

costOp

Window / process cost per record in ms

costOp=200

seed

Random seed

seed=7

speed

Playback speed: 0.25, 0.5, 1, 2, 4, 8 or 16

speed=2

hop

Hop time in seconds (0.1–5) or clock

hop=1

Scenarios:

example= Shows

event-time

Processing-time vs event-time windows on the same records; reproducible event-time results (open)

watermarks

Bounded out-of-orderness, the minimum across inputs, an idle partition stalling every window, withIdleness, watermark alignment (open)

windows

Tumbling, sliding and session windows; late records dropped, re-fired with allowed lateness, or sent to a side output (open)

state

Keyed state per key group, state TTL, HashMap vs RocksDB, incremental checkpoints (open)

checkpoints

Barriers, alignment, acknowledgements and completion; unaligned checkpoints (open)

recovery

A lost TaskManager, restart from the last checkpoint, Kafka offsets rewound, duplicates in an at-least-once sink (open)

exactly-once

A two-phase-commit Kafka sink: pre-commit on the barrier, commit on completion, abort on failure, read_committed without duplicates (open)

backpressure

Credit-based flow control, backpressure up to Kafka lag, slow aligned checkpoints, unaligned ones, fixing the bottleneck (open)

rescale

Key groups, stop with savepoint, restore at a new parallelism, the max-parallelism limit (open)

playground

Your own pipeline and events (open)

Runs entirely in your browser; nothing you type leaves this page.