Phase 9: Real-World Choke Points, Capacity Planning & Telemetry¶
Audience: Principal Site Reliability Engineer & Distributed Systems Performance Specialist
Source References:flink-runtime/src/main/java/org/apache/flink/runtime/metrics/
1. Production Choke Points & Root Cause Pathologies¶
1.1 Checkpoint Alignment Timeout Disaster¶
When backpressure builds, network channels fill with data records.
- In the Flink Web UI under Checkpoints -> Details:
- Sync Duration: 2 ms
- Async Duration: 400 ms
- Alignment Duration: 58,400 ms (Exceeds 60s timeout!)
- Symptom: Checkpoints fail repeatedly with CheckpointExpiredException. Flink restarts the entire streaming job, causing an infinite crash-and-restart loop!
- Fix: Enable Unaligned Checkpoints (enableUnalignedCheckpoints()).
1.2 Data Skew on keyBy()¶
When data is partitioned by key (stream.keyBy(...)), an uneven distribution of keys (e.g. 80% of events belong to tenant_id: "VIP_CUSTOMER") causes a single Task Slot to receive 80% of total workload:
Data Skew Telemetry in Web UI:
Subtask 0: busyTime = 4%, recordsIn = 1,000 /sec
Subtask 1: busyTime = 3%, recordsIn = 1,200 /sec
Subtask 2: busyTime = 99%, recordsIn = 95,000 /sec <=== SKEW BOTTLENECK!
Subtask 3: busyTime = 5%, recordsIn = 1,100 /sec
The Two-Stage Salt Aggregation Pattern:¶
// Phase 1: Local Pre-Aggregation with Random Salt (e.g. 0 to 9)
DataStream<AggregatedResult> preAgg = source
.map(event -> new SaltedEvent(event, random.nextInt(10)))
.keyBy(SaltedEvent::getSaltedKey) // Evenly spreads across ALL 4 subtasks!
.window(TumblingEventTimeWindows.of(Time.minutes(1)))
.aggregate(new PartialSum());
// Phase 2: Global Merge of the 10 Partial Results
DataStream<FinalResult> finalResult = preAgg
.keyBy(PartialResult::getOriginalKey)
.window(TumblingEventTimeWindows.of(Time.minutes(1)))
.aggregate(new FinalSum());
2. Diagnostics: Thread Dumps & CPU Flame Graphs¶
The Flink Web Dashboard provides native, zero-downtime profiling tools:
2.1 Thread Dump Analysis¶
Click TaskManagers -> Select Worker -> Thread Dump:
- Look for threads in TIMED_WAITING or BLOCKED:
"Task Slot-1" prio=5 tid=0x7fff0 nid=0x1803 runnable
at org.rocksdb.RocksDB.get(Native Method)
at org.apache.flink.contrib.streaming.state.RocksDBValueState.value()
2.2 CPU Flame Graphs & Kryo Serialization Tax¶
Enable Flame Graphs in the Web UI:
- If a large portion of the flame width is occupied by com.esotericsoftware.kryo.*:
- The Pipeline is Trapped in Fallback Serialization!
- Flink could not determine a strict POJO schema and fell back to slow generic Java reflection (Kryo).
- Fix: Enforce POJO conventions (public getters/setters, default no-arg constructor) or register custom Avro/Protobuf serializers to eliminate 80% of CPU overhead!
3. Backpressure Monitoring Dashboard¶
Flink Backpressure Visual Indicators:
[ Source ] ──► [ Transform ] ──► [ Aggregate ] ──► [ Sink ]
[RED] [RED] [RED] [GREEN]
(Backpressured) (Backpressured) (Bottleneck) (Idle)
- RED Status: Task is experiencing \(> 50\%\) backpressure.
- Follow the red chain downstream.
- The last red operator in the chain is the root bottleneck! Inspect its external dependencies (e.g. slow database writes, locks, garbage collection).