Skip to content

Asynchronous Top-N memory checkpoints

Applies to: append-only Top-N on the memory backend

Flink's heap backend captures a copy-on-write state-table view at an aligned checkpoint barrier and serializes that view on its asynchronous checkpoint thread. Native Top-N previously encoded every key-group IPC payload inside snapshotState, so the task could not resume until the complete state had crossed Rust → Java and been installed in canonical keyed state.

The memory path now captures an immutable native snapshot token at the barrier. Payload rows retain their existing Arc<OwnedRow> buffers; the capture copies the partition keys, small sort keys, and buffer vectors needed to isolate the checkpoint from subsequent input. Each immutable partition is then installed as a lazy Flink heap-state value. Flink's normal asynchronous heap-state serializer calls back into Rust to build the IPC payload. The token is released deterministically after its last partition is encoded, with a Cleaner fallback for cancelled checkpoints.

The state contract remains backend-independent and rescalable: there is one checksummed value per owned key group, canonical savepoints use the same serializer, and restore accepts both the new v2 lazy descriptor and the previous v1 chunked-byte descriptor. Retracting and update-fast Top-N keep the v1 synchronous path until they receive their own immutable capture shape.

Measurement

On the release+mimalloc 2M-event q19 exactly-once Kafka loop (parallelism 4, one-second aligned checkpoints), a matched 35-second CPU profile moved all 401 native partition-encoding samples under Flink's AsyncOperations thread. Task-thread checkpoint work fell from 506/18,177 samples (2.8%) to 213/17,288 (1.2%), a 56% reduction in checkpoint CPU blocking the task. Both 75-second loops completed 9 jobs; median execution time moved from 7.7 s to 7.5 s, so no headline throughput gain is claimed. The technique is retained for the measured barrier-critical-path reduction, not presented as a larger end-to-end Q19 speedup.

The diagnostic property streamfusion.state.asyncMemorySnapshots.enabled=false selects the legacy synchronous path for matched profiling; production defaults to the asynchronous path.