PrepZone Logo
PrepZone

Linearizability vs Serializability

Single-operation vs transaction ordering guarantees — critical for ShardPay double-spend prevention.

Why this matters

  • Conflating linearizability and serializability is a common senior interview trap — they apply at different granularities.
  • Distributed locks and leader election need linearizable registers; multi-statement transfers need serializable transactions.
  • Jepsen and formal tests verify linearizability claims — marketing "strong consistency" without specifying which guarantee is a red flag.
  • ShardPay's architecture uses linearizable single-account updates inside serializable cross-table transactions on one shard.
LinearizableStrongest — single copy illusion
SequentialTotal order on all ops
CausalPreserves cause-effect
EventualConverges over time
Stronger guarantees cost latency and availability.

Two ordering guarantees

A balance read immediately after a transfer must return the new value — that is linearizability on the account register. A batch job that debits one account and credits another on the same shard must execute as if no other transaction interleaved — that is serializability on the transaction schedule.

Linearizability is about individual operations and real-time ordering. Serializability is about multi-operation transactions and equivalent serial execution. ShardPay needs both, at different layers of the stack.

Definitions

  • Linearizability — Each operation appears to take effect instantaneously at some point between its invocation and response, respecting real-time order. ShardPay's GET /balance after a successful POST /transfers must return the post-debit balance — not a value from before the transfer completed.
  • Serializability — The result of concurrent transactions is equivalent to some serial execution of those transactions. ShardPay's ledger applies debit(A) + credit(B) inside one transaction so no concurrent transfer can observe A debited but B not yet credited.
  • Strict serializability — Serializable order that also respects real-time precedence. ShardPay's single-shard transfer path targets strict serializability: if transfer T1 completes before T2 starts, the serial order must place T1 before T2.
  • Compare-and-set (CAS) — Atomic read-modify-write primitive underpinning linearizable updates. ShardPay's optimistic balance update uses UPDATE accounts SET balance = :new WHERE id = :id AND balance = :expected — the database CAS enforces single-writer semantics per row.

Linearizability at the register layer

Distributed systems literature often models a key-value register. ShardPay's account balance is logically one register per accountId. Leader-based replication with quorum reads/writes provides linearizable access when configured correctly.

Walkthrough: Concurrent balance reads during transfer

  1. Account A has balance $1,000.
  2. Thread 1 starts transfer debiting $200 at wall time T0; commit completes at T1.
  3. Thread 2 issues linearizable read at T0.5 (during transfer). It may return $1,000 or wait — never $800.
  4. Thread 3 issues linearizable read at T2 (after commit). It must return $800.
  5. Any read that overlaps the write interval either sees before-state or after-state — never an impossible middle.
Java
// Linearizable balance read via leader + quorum (conceptual)
public long readBalanceLinearizable(String accountId) {
    return leader.readWithQuorum(accountId, ReadConcern.QUORUM);
}

// Linearizable update via CAS on leader
public boolean debitIfSufficient(String accountId, long amount, long expectedBalance) {
    return leader.compareAndSet(accountId, expectedBalance, expectedBalance - amount);
}

Serializability at the transaction layer

Within one shard, ShardPay uses MVCC with serializable isolation for transfer transactions: debit source, credit destination, insert audit row, bump daily limit counter — all commit or abort together.

Transaction-level guarantees

  • Serializable isolation — Prevents anomalies like write skew where two transactions each read a condition, both pass, and together violate an invariant. ShardPay rejects concurrent transfers that would together exceed a daily limit even if each alone looked fine at read time.
  • Snapshot isolation (weaker) — Each transaction sees a consistent snapshot; write skew still possible. ShardPay moved from snapshot to serializable on the ledger after a write-skew incident on shared merchant limit rows.
  • Distributed serializability — Serializable across shards requires coordination (2PC, saga, or single-shard design). ShardPay colocates both legs of a transfer on one shard via hash(min(accountA, accountB)) to keep serializability local.
  • Linearizable but not serializable — Individual CAS ops can be linearizable while a multi-step workflow across keys is not serializable without a transaction boundary. ShardPay wraps multi-row updates in explicit DB transactions, not chains of separate CAS calls.

Example: Write skew on daily limits

Two transfers of $30,000 each run concurrently on the same merchant account with a $50,000 daily cap. Under snapshot isolation, both read dailyTotal=$0, both pass the check, and both commit — $60,000 exits. Under serializable isolation, one transaction aborts with SERIALIZATION_FAILURE; ShardPay's client retries with backoff. The merchant sees one success and one "limit exceeded" — correct behavior.

Testing and operating strong guarantees

Verification

  • Jepsen — Fault-injection framework that checks linearizability under partitions and crashes. ShardPay runs Jepsen suites against staging ledger shards before major replication upgrades.
  • Formal register tests — History checker builds a graph of operations and searches for linearization points. Used in CI for ShardPay's custom in-memory ledger prototype.
  • DB isolation levels — Postgres SERIALIZABLE, Cockroach serializable default — know what your engine actually provides. ShardPay's per-shard Postgres runs default_transaction_isolation = serializable.
  • When to relax — Analytics replicas use READ COMMITTED — no financial writes. Document the boundary so engineers do not run ad-hoc fixes on the wrong connection pool.

Quick recall

Everything you need if you only revisit this box.

  1. Linearizability is per-object real-time order; serializability is about transaction interleaving.
  2. ShardPay uses linearizable registers inside serializable single-shard transactions.
  3. Cross-shard serializability needs sagas or colocation — payments colocate by account pair hash.

Test yourself

Answer these before moving on — recall is what makes it stick.