Lesson 08 · The hidden bill

Every copy asks which truth wins.

A single transaction once guarded the whole change. Across replicas and shards, delays and failures make intermediate states visible. Consistency is not one switch; it is a choice made for each operation.

IsolationCAPIdempotencySagas

01 · The baseline

One database already makes strong promises.

A PostgreSQL transaction gives us the familiar ACID foundation: changes are all-or-nothing, valid rules remain true, concurrent work is isolated according to a chosen level, and committed work survives. WAL makes durable recovery possible; locks and multi-version concurrency control shape what concurrent transactions can observe.

Isolation is not simply on or off. PostgreSQL offers different views of concurrent work, each trading stronger guarantees for more waiting or more retries.

Transaction isolation inside one PostgreSQL database
LevelWhat a transaction seesApplication consequence
Read CommittedEach statement gets a fresh snapshot of committed data.Two statements in one transaction can see different committed results.
Repeatable ReadThe transaction keeps one stable snapshot.Conflicting updates can still require an abort.
SerializableResults behave as if transactions ran one at a time.PostgreSQL may abort a transaction; the application must retry it.

See PostgreSQL’s official Transaction Isolation documentation for the exact guarantees and retry behavior.

02 · A race in one row

Read, calculate, write can lose a valid update.

Two workers read inventory 10. Each sells one item, calculates 9, and writes 9. Both transactions can commit, but only one decrement remains. The second assignment overwrote the first worker’s decision with the same stale calculation.

Worker Areads 10 → writes 9
Inventory10 → 9one sale disappeared
Worker Breads 10 → writes 9

The best fix is often to express the operation atomically inside the database: UPDATE inventory SET quantity = quantity - 1 WHERE … AND quantity > 0. PostgreSQL sees the dependency and serializes the row updates. Other valid tools are SELECT … FOR UPDATE, or Serializable isolation with a retry loop.

Do not ask the application to protect a rule the database can express in one atomic statement.

03 · When the wire breaks

A network partition forces a choice.

CAP is about the moment connected machines can no longer communicate reliably. The partition is not an option we select; it is the failure already happening. During it, the system must choose between consistency—refuse some operations rather than risk conflicting truths—or availability—continue answering and accept that copies may diverge.

Consistency during partitionStop before disagreement

Synchronous or quorum paths may wait or reject work when enough members cannot confirm it.

Availability during partitionAnswer with a local truth

Asynchronous paths can keep serving, but acknowledged writes or reads may later need reconciliation.

Most days there is no partition, yet replication still crosses a network. PACELC adds the daily question: else, when the network is healthy, do we pay extra latency for stronger consistency or accept weaker consistency for faster responses? Replication’s synchronous-versus-asynchronous choice was already this tradeoff in concrete form.

04 · Name the promise

Different operations deserve different consistency.

Useful consistency promises
PromiseMeaningPossible use
LinearizableEvery operation appears to occur at one real-time point.Claiming a unique username or spending a balance.
Read-your-writesA user sees their own completed changes.Showing the address immediately after saving it.
Monotonic readsOnce a user sees a version, later reads never go backward.Progress, status, or feeds routed among replicas.
EventualCopies converge when updates stop, without a bound on immediate visibility.Like counts, analytics, and reconstructable projections.

“The system is eventually consistent” is too broad to guide engineering. State the promise at the operation boundary. Payment creation may need uniqueness and read-your-writes; a recommendation count may safely arrive later. Paying for the strongest guarantee everywhere wastes availability and latency.

05 · Messages repeat

Retries must not repeat the business effect.

Networks fail ambiguously. A client times out after sending a payment request and cannot know whether the server committed it. Retrying is necessary, but blindly retrying can charge twice. An idempotency key gives every logical request a stable identity and lets the database make duplicate attempts harmless.

INSERT INTO payments (idempotency_key, amount)
VALUES ($1, $2)
ON CONFLICT (idempotency_key) DO NOTHING;

The key needs a unique constraint and a stored result or status that later retries can return. The rule applies beyond HTTP: consumers, job runners, outbox relays, and migration workers all retry after uncertain failure. “At least once” delivery becomes safe only when the effect is idempotent.

06 · More than one authority

A saga replaces one global rollback with local repairs.

An order workflow may reserve inventory on one shard, charge a payment service, and schedule delivery elsewhere. Holding locks across all three systems with a distributed transaction is fragile and can block progress during failures. A saga commits local transactions one at a time and records how to compensate if a later step fails.

1Reserve stockundo: release
→
2Charge paymentundo: refund
→
3Create shipmentundo: cancel

Compensation is a new business action, not time travel: a refund does not erase the fact that a charge was briefly visible. Intermediate states must be modeled, exposed carefully, retried idempotently, and reconciled when automation cannot finish.

07 · The complete map

Every scaling tool buys one thing and sends a bill.

The database scaling decision matrix
ToolWhat it buysWhat it costs
IndexesFewer pages touched per querySlower writes, storage, buffer-pool competition
The write pathDurability at sequential-write speedWrite amplification, dirty-page flushing, checkpoint spikes
PartitioningPruning, smaller maintenance units, cheap retentionRigid key, multiplied indexes, planning overhead
ShardingIndependent write, storage, CPU, and memory capacityRouting, fan-out, lost joins, distributed transactions, rebalancing
ReplicationRead throughput and recovery copiesLag, loss or reduced availability, failover coordination

Consistency is the bill beneath every copy and split. It appears as acknowledgement latency, stale reads, retries, fencing, idempotency, compensation, and reconciliation. It cannot be removed; it can only be made explicit and paid where the product truly needs it.

01Keep hot data in memory.

Storage trips dominate; understand the working set before changing architecture.

02Copy for reads. Split for writes.

Replicas add readers; shards add independent writers.

03Shape and key must agree.

Index prefix, partition key, and shard key help only queries that carry them.

04Diagnose before choosing.

Most “we need sharding” stories still end at an index, a query, or a working-set fix.

The Old Dragon“Now you may split the realm—not because it sounds large, but because you can name the resource that ran out and the price you accept.”

The Dragon’s Final Reckoning

Where we stand

We began with a slow query and ended with a vocabulary for choosing the smallest architecture that solves the measured limit.

What we learnedConsistency is chosen per operation

Isolation, freshness, availability, retries, and compensation are explicit product promises.

What we solvedThe first question at the gate

We no longer ask “How do we shard?” before asking which resource has run out.

What remainsMeasure the real system

Plans, buffer reads, cache misses, lag, shard load, and business invariants must confirm the design.

Our system nowA justified architecture

Every index, partition, shard, or replica must earn its place with evidence.

Bonus lesson · Advanced

The Keeper’s Judgement

You know every technique. Now decide which one a real problem calls for, and in what order.

The Old Dragon has one more counsel.