Back to Spark Streaming & Structured Streaming
Q20Question 20 of 22

Flink checkpoint vs savepoint

Key Concepts
  • Checkpoints are automatic, periodic, Flink-owned snapshots optimized for low-overhead crash recovery.
  • Savepoints are user-triggered, portable snapshots for planned lifecycle operations like upgrades, rescaling, and migration.
  • Checkpoints may use backend-specific incremental formats; savepoints use a canonical, self-contained, version-portable format.
  • Savepoint restore matches state to operators by their uid(), so every stateful operator must have a stable unique ID.
  • Checkpoints are deleted when superseded; savepoints persist until explicitly deleted by the operations team.
  • Test savepoint-restore as part of the deployment pipeline to catch broken state migrations before production.

Definition

Checkpoints are Flink's automatic, cheap, self-owned snapshots for crash recovery, while savepoints are user-triggered, portable, durable snapshots for upgrades, rescaling, and planned changes.
  • Checkpoint – Automatic, periodic snapshot taken and owned by Flink purely for fault tolerance; optimized for low overhead, may use incremental format, and is typically deleted when superseded.
  • Savepoint – User-triggered snapshot stored in a stable, portable format designed for operational actions such as upgrades, rescaling, and state migration; owned by the user and persisted until explicitly deleted.
  • Portability – Savepoints work across Flink versions and topology changes as long as operators have stable unique IDs via uid(...).
  • Lifecycle – Checkpoints are managed by Flink; savepoints are managed by the operations team.
  • Format – Checkpoints may be backend-specific and incremental; savepoints use a canonical, self-contained format.

The National Bank of India's system takes two kinds of backups. A checkpoint is like the automatic, frequent autosave the system makes every few seconds so that if the power trips it can recover to a moment ago. Nobody asks for it, and old autosaves are discarded. A savepoint is like a deliberate, labeled full export the operations team requests before upgrading the software or adding more servers. It is a clean, portable archive the team names and keeps until they decide to delete it.

Understanding the Concepts

A checkpoint is triggered automatically by the checkpoint coordinator on the interval you configure. It is owned and managed by Flink, which decides when to create and delete it. Checkpoints prioritize low overhead.

JAVA
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

StreamExecutionEnvironment env =
    StreamExecutionEnvironment.getExecutionEnvironment();

// Automatic checkpoints every 10 seconds
env.enableCheckpointing(10_000);
env.getCheckpointConfig().setCheckpointStorage(
    "s3://nbi-flink-checkpoints/");

// Checkpoints are managed by Flink:
// - Created automatically on interval
// - Old ones deleted when newer completes
// - May be incremental (RocksDB)

A savepoint is triggered manually by an operator, stored in a portable format, and persists until explicitly deleted. It is designed for planned lifecycle operations.

BASH
# Take a savepoint
flink savepoint <jobId> s3://nbi-savepoints/fraud-scoring-v2

# Stop with final savepoint (graceful)
flink stop --savepoint s3://nbi-savepoints/pre-upgrade <jobId>

# Restore from savepoint
flink run -s s3://nbi-savepoints/pre-upgrade \
    --allowNonRestoredState \
    fraud-scoring-v3.jar

How are they different?

| Aspect | Checkpoint | Savepoint |
|---|---|---|
| Trigger | Automatic (periodic) | Manual (user-initiated) |
| Owned by | Flink | Operations team |
| Purpose | Crash recovery | Upgrades, rescaling, migration |
| Format | May be backend-specific, incremental | Canonical, portable, self-contained |
| Lifecycle | Deleted when superseded or job stops | Persists until explicitly deleted |
| Portability | Not guaranteed across versions | Designed for cross-version restore |
| Speed | Optimized for low overhead | May be heavier (full format) |

JAVA
// Checkpoint: you never think about it
// Job crashes → Flink restores from latest checkpoint automatically

// Savepoint: deliberate operation
// Deploy new version → take savepoint → stop old → start new from savepoint

Why are operator UIDs essential for savepoints?

Savepoint restore matches state to operators by their assigned unique IDs. Without stable UIDs, a code change can orphan state and fail the restore.

JAVA
import org.apache.flink.streaming.api.datastream.DataStream;

// CORRECT -- stable UIDs on every stateful operator
DataStream<String> result = txnStream
    .keyBy(txn -> txn.getAccountId())
    .process(new BalanceTracker())
    .uid("balance-tracker")          // stable UID
    .name("Balance Tracker");

result
    .keyBy(alert -> alert.getAccountId())
    .process(new FraudScorer())
    .uid("fraud-scorer")             // stable UID
    .name("Fraud Scorer");

// WRONG -- no UIDs, savepoint restore breaks on code change
txnStream.keyBy(txn -> txn.getAccountId())
    .process(new BalanceTracker());  // no uid()!
// If code changes reorder operators, state cannot be matched

When do you use each?

Checkpoints are always on for crash recovery. Savepoints are for planned lifecycle events: code upgrades, parallelism changes, Flink version upgrades, state migration, and debugging.

BASH
# Scenario 1: Code upgrade
flink stop --savepoint s3://nbi-savepoints/v2-pre-upgrade <jobId>
flink run -s s3://nbi-savepoints/v2-pre-upgrade fraud-scoring-v3.jar

# Scenario 2: Rescale from 4 to 8 slots
flink stop --savepoint s3://nbi-savepoints/pre-rescale <jobId>
flink run -s s3://nbi-savepoints/pre-rescale -p 8 fraud-scoring.jar

# Scenario 3: Debug a production issue
flink savepoint <jobId> s3://nbi-savepoints/debug-snapshot
# Restore locally with small test data for debugging

What about checkpoint retention?

By default checkpoints are deleted when the job stops. You can configure retention so a checkpoint survives cancellation for emergency recovery.

JAVA
import org.apache.flink.streaming.api.environment.CheckpointConfig;

// Retain checkpoint on cancellation
env.getCheckpointConfig().setExternalizedCheckpointCleanup(
    CheckpointConfig.ExternalizedCheckpointCleanup
        .RETAIN_ON_CANCELLATION);
// Now the last checkpoint survives job cancellation
// Useful for emergency recovery when savepoint was not taken

What are common mistakes?

The most common mistake is not assigning stable UIDs to stateful operators, which makes savepoint restore fail on code changes. Another is relying solely on checkpoints for planned upgrades, which may not be portable.

JAVA
// WRONG -- no UIDs on stateful operators
// Savepoint taken, code refactored, restore fails!

// CORRECT -- always assign uid() to every stateful operator
stream.process(new BalanceTracker()).uid("balance-tracker");
stream.process(new FraudScorer()).uid("fraud-scorer");
// Savepoint restore matches state by UID, code changes are safe

What should a senior engineer know?

Test savepoint-restore as part of your deployment pipeline. Discovering a broken state migration in production during an upgrade is extremely costly for a bank. Assign stable UIDs from day one, take savepoints before every planned change, and retain at least one checkpoint on cancellation as a safety net.

Visual Overview

DIAGRAM
  Checkpoint vs Savepoint Lifecycle

  Checkpoints (automatic, Flink-owned):
  ──▶ CP1 ──▶ CP2 ──▶ CP3 ──▶ CP4 ──▶ CP5
       │       │       │       │       │
       ✗       ✗       ✗       ✗       ✓ (latest kept)
  Old ones automatically deleted
  Used for: automatic crash recovery

  Savepoints (manual, user-owned):
  ──▶ SP-v1 ────────── SP-v2 ────────── SP-v3
       │                │                │
       ✓ (kept)         ✓ (kept)         ✓ (kept)
  Persist until explicitly deleted
  Used for: upgrades, rescaling, debugging

  Upgrade workflow:
  ┌───────────┐    ┌───────────┐    ┌───────────┐
  │ Job v2    │──▶ │ Savepoint │──▶ │ Job v3    │
  │ running   │    │ taken     │    │ restored  │
  │           │    │ (portable)│    │ from SP   │
  └───────────┘    └───────────┘    └───────────┘
  Requires uid() on every stateful operator

Key Takeaway

Checkpoints and savepoints are both consistent snapshots of a Flink job's state, but they serve different purposes. A checkpoint is automatic, periodic, owned by Flink, and optimized for low-overhead crash recovery. Old checkpoints are deleted when newer ones complete, and the format may be backend-specific and incremental. You never think about checkpoints during normal operation; if a task manager dies, Flink restores silently.

A savepoint is user-triggered, stored in a stable portable format, and persisted until you explicitly delete it. Its purpose is planned lifecycle operations: code upgrades, parallelism changes, Flink version migrations, and debugging. It works across versions and topology changes as long as operators carry stable UIDs assigned with uid(...), because savepoint restore matches state to operators by those IDs.

The critical practice is assigning a uid() to every stateful operator from day one. Without it, any code refactoring breaks savepoint restore. Test savepoint-restore as part of your deployment pipeline, because a broken state migration discovered during a production upgrade is extremely costly.

At the National Bank of India the fraud-scoring job ran with automatic checkpoints for crash recovery and the team took savepoints before every deployment. When deploying a new fraud model that added operators and scaled from 4 to 8 slots, they stopped with a savepoint, started the new version from it, and accumulated per-account scores carried cleanly because every operator had a stable UID.

Remember one sentence: Checkpoints are cheap, automatic, Flink-owned snapshots for crash recovery, while savepoints are portable, retained, user-owned snapshots for planned changes, and stable operator UIDs are essential for savepoint restore.

---

Share
Use ← → arrow keys to navigate