Skip to content
About
Main content

Exactly-once: checkpoint plus transactional sink

Why is the checkpoint the commit point of a stream job, and what does that cost in latency and timeouts?

What a stream processor provides is exactly-once effect, not delivery: duplicates still happen and are made harmless (exactly-once is about effects). Here the job that never ends adds one thing: the is the commit point.

The mechanism

It composes three things:

  1. The checkpoint is a consistent cut containing source offsets, so state and input position recover together.
  2. The sink joins a two-phase commit, driven by the checkpoint's life cycle:
    • pre-commit when the passes the (the sink flushes its pending output into an open transaction, but does not commit it);
    • commit when the engine announces checkpoint complete (all have saved their state);
    • abort, and recover pending transactions, on restore.
  3. After a crash, the job restores the last complete checkpoint. Output written after it was in an uncommitted transaction and is rolled back. Records are then replayed from the saved . Each output appears exactly once in committed form.
          records ...|barrier n|... records ...|barrier n+1|...
Sink:     [ transaction n open: pre-commit at barrier n ]
          [ commit when checkpoint n completes ]  -> output becomes visible
          crash before completion -> abort, restore checkpoint n-1, replay

What the checkpoint as commit costs

The general costs of a transactional sink are fault-tolerance's. In a stream job two of them are set by the checkpoint.

1. Output is invisible until the checkpoint completes. So : with a 10-second interval, results appear 10 to 20 seconds late. (Ana's 30 seconds is her checkpoint interval plus duration.)

2. The transaction must outlive the checkpoint and the recovery. The sink holds an open transaction for the whole interval, so its timeout must exceed the maximum checkpoint duration plus the worst-case recovery time.

Two timeouts configured independently, with a hidden ordering constraint between them, is a classic production failure.

Where the sink can by a key derived from the input, writes need no transaction at all and remove both costs (the three sources of idempotence). Either way the replayed computation must be deterministic, or the output differs on recovery and nothing detects it (determinism).