LESSON
Day 489: Linearizability vs Serializability
The core idea: Linearizability tells Harbor Point what a single read or write may observe in real time; serializability tells Harbor Point whether a whole transaction behaved like it ran alone. They solve different correctness problems, and production systems often need one, the other, or strict serializability when both matter at once.
Today's "Aha!" Moment
In 057.md, Harbor Point built a booking authority cluster that can choose one log entry safely. That still does not answer the question an API owner gets from product: after the booking service returns 200 OK, what is the next caller allowed to see? The availability widget, the cabin-upgrade workflow, and the finance ledger do not all need the same guarantee.
The useful distinction is this: linearizability is about the observed order of individual operations. If agent Sofia books suite S12 and gets success at 14:03:12, a later availability read at 14:03:13 must not say available if the API promises linearizable semantics. Serializability is about the effect of an entire transaction across multiple objects. If an upgrade workflow reads the guest record, the cabin inventory row, and the payment-hold row, serializability means the whole unit behaves like it ran alone in some one-at-a-time order.
That is why the terms are easy to confuse and dangerous to merge. "Serializable" sounds stronger because it mentions whole transactions, but plain serializability does not require real-time order. "Linearizable" sounds globally strong, but per-key linearizable operations can still violate a cross-row invariant when two transactions interleave. Harbor Point needs the difference because the booking page is harmed by stale reads, while the upgrade workflow is harmed by multi-record anomalies.
Why This Matters
Harbor Point sells suites through call-center agents, the website, and partner travel portals. After the consensus lesson, the team routed booking writes through a leader-backed replicated log. They then made two product choices. The website read availability from local followers to shave latency. The upgrade workflow moved guests between cabins with a sequence of conditional writes against separate rows. Both changes looked reasonable in isolation. Together they created two different incident classes.
The first incident is user-visible inconsistency. An agent confirms suite S12, yet a travel partner still sees S12 as free for a few seconds because its read came from a stale replica. That is not a transaction anomaly; it is a broken real-time visibility contract. The second incident is a broken invariant. Harbor Point must keep at least one wheelchair-accessible cabin unsold until medical-clearance cutoff. Two agents each see that one accessible cabin remains after their sale, and each independently sells one. Every single row update can be linearizable, but the policy still fails because no serializable transaction protected the set of cabins as one unit.
The trade-off is operational, not academic. Linearizable reads usually force the request through the current leader or a quorum-backed read fence, which costs latency and leader capacity. Serializable transactions preserve multi-row invariants, but they add lock waits, transaction aborts, and retry logic under contention. If Harbor Point needs both "the next read must reflect the last completed write" and "the whole multi-row workflow behaves like one atomic step," the real requirement is strict serializability, which is more expensive still.
Core Walkthrough
Part 1: Two questions, two guarantees
Keep the Harbor Point scenario concrete. There are two APIs touching the same voyage inventory.
The first is an availability check:
GET /voyages/V17/suites/S12
If booking transaction B1 reserves suite S12 and returns success, a later availability request must not observe an older state if Harbor Point promises linearizability. Each operation has to appear as if it took effect at one instant between call and response, and real-time order matters. "Later call sees earlier completed write" is the contract.
The second is an upgrade workflow:
BEGIN
read guest #8841
read suite S12
read suite S14
update guest assignment to S14
mark S12 vacant
mark S14 occupied
release old payment hold
create new hold
COMMIT
Here the question is different. Harbor Point does not care only about the visibility of one row. It cares that the whole workflow preserves invariants: one guest has one cabin, the destination cabin is not double-assigned, and the payment hold matches the assignment. Serializable isolation says the transaction must have the same effect as if all concurrent upgrade transactions ran one at a time in some serial order.
That difference is the core of the lesson:
- linearizability answers "what may the next operation observe in real time?"
- serializability answers "did concurrent transactions preserve the same outcome as some one-at-a-time execution?"
One is a property of operations on an object or API surface. The other is a property of transactions over a read/write set.
Part 2: How the mechanisms differ internally
Linearizability needs a point of authoritative visibility. In Harbor Point's booking authority, that usually means the current leader, or a read path that first confirms the leader still holds authority for the latest committed log position. A stale follower can hold the right bytes eventually and still be the wrong place to answer "is S12 free right now?"
14:03:12 Agent A -> leader: reserve S12
14:03:12 leader commits slot 812 = "S12 sold to #8841"
14:03:12 leader -> Agent A: 200 OK
14:03:13 Partner portal -> stale follower: read S12
14:03:13 follower replies "available" <- not linearizable
14:03:13 Partner portal -> leader/read-index path: read S12
14:03:13 reply "sold to #8841" <- linearizable
Serializability uses a different mechanism. The storage engine does not need every read to be the newest committed value at wall-clock time. It needs the committed transactions to fit a valid serial order with no contradictory interleaving. Databases implement that with locks, predicate locks, optimistic validation, MVCC plus serialization checks, or deterministic transaction ordering. The internal question is not "did this read hit the latest leader state?" It is "can these reads and writes commit together without creating an impossible serial schedule?"
The accessible-cabin rule makes this concrete. Harbor Point reserves two cabins, A12 and A14, for emergency relocation until cutoff, and policy says at least one must remain unsold.
T1: read A12=free, A14=free
T2: read A12=free, A14=free
T1: sell A12
T2: sell A14
If Harbor Point performs these as separate per-row linearizable writes, every individual write can look perfectly ordered. There is no stale read on either row at the moment it is written. But the combined outcome leaves zero protected cabins, which no serial one-at-a-time execution should allow given the policy. Serializability catches that class of anomaly by treating the whole transaction, including the predicate "at least one of these cabins remains free," as the unit that must be isolated.
This also explains why plain serializability is not the same as linearizability. A database can be serializable yet still allow a read-only transaction to observe an older snapshot if that snapshot can be placed earlier in the serial order. If Harbor Point product language says "once the booking confirmation screen succeeds, any later availability check anywhere must reflect it," serializability alone is not enough. That stronger requirement is strict serializability, also called external consistency in some systems: serializable transactions plus real-time order.
Part 3: Choosing the right guarantee in production
Harbor Point should ask three separate design questions instead of one vague "is this strongly consistent?" question.
Use linearizability when the API contract is about immediate visibility of a single decision point: lock acquisition, leader election, inventory availability for one suite, feature-flag reads, or idempotency-key lookups. The trade-off is that low-latency follower reads become harder to justify, and cross-region read paths often become slower because they must prove freshness.
Use serializability when correctness depends on a multi-object invariant: moving a guest between cabins, decrementing quota while recording an audit row, applying a refund while updating the invoice ledger, or enforcing "one active hold per guest and voyage." The trade-off is contention management. Under load, the system will pay in blocking, deadlocks, aborts, or higher retry volume.
Ask for strict serializability when both contracts matter at once: a multi-row workflow must behave atomically, and later callers must observe it in real-time order once it commits. That is the point where time, commit ordering, and external visibility become design constraints rather than implementation details. Harbor Point can get there, but it should budget for more coordination, more precise clock or lease discipline, and more care around cross-region latency. That is why the next lesson turns to time, clocks, and global ordering.
Failure Modes and Misconceptions
-
"Our database is serializable, so every later read must see the latest completed write." This is tempting because "serializable" sounds like the top-shelf guarantee. The corrective model is that plain serializability constrains transaction interleavings, not wall-clock visibility. If the product contract depends on real-time order, Harbor Point needs linearizable reads or strict serializable transactions.
-
"Every row is stored in a linearizable system, so cross-row business rules are automatically safe." This fails on write-skew-style invariants. Harbor Point can still violate "leave one accessible cabin free" if two transactions each make a locally correct row update without serializable isolation over the whole predicate.
-
"Consensus-backed writes automatically make reads linearizable." Consensus solves safe log agreement, which the previous lesson covered. A stale follower, a lease that was not checked, or a read path that ignores the latest commit index can still return old data after a completed write.
-
"Linearizability is always the better default because it is stronger." Stronger for one object is not broader for a whole workflow. Harbor Point should not pay leader-routed read latency for every analytics query, and it should not confuse low-latency single-key correctness with transactional safety.
Connections
Connection 1: 057.md gave Harbor Point one authoritative log
That lesson explained how the cluster chooses one history safely. This lesson explains what clients may observe from that history: fresh single-operation visibility, transaction isolation, or both.
Connection 2: 055.md showed why multi-step distributed workflows need explicit correctness boundaries
The same discipline applies here. Once a workflow touches several records, the question is no longer just "was the write replicated?" but "what invariant spans the whole unit of work, and what isolation level actually protects it?"
Connection 3: 059.md will explain why clocks and ordering enter the design again
Strict serializability and external consistency require the system to connect commit order to real time. That makes lease validity, commit timestamps, and uncertainty windows operational topics, not just theory terms.
Resources
- [ARTICLE] Linearizability versus Serializability
- Focus: Read the examples that separate stale reads from transaction anomalies; they map directly to Harbor Point's availability and upgrade paths.
- [PAPER] Linearizability: A Correctness Condition for Concurrent Objects
- Focus: Pay attention to the definition of a linearization point and the requirement to preserve real-time precedence.
- [DOC] etcd API Guarantees
- Focus: Notice how the API distinguishes linearizable reads from weaker serializable reads even though both run on a consensus-backed system.
- [PAPER] Spanner: Google's Globally-Distributed Database
- Focus: Use the external consistency sections to see what extra machinery is needed when serializable transactions must also respect real-time order.
Key Takeaways
- Linearizability is about real-time visibility of individual operations; serializability is about whether whole transactions behave like a serial schedule.
- A system can give Harbor Point linearizable per-key operations and still violate a multi-row invariant, or give serializable transactions without promising that later callers see earlier commits immediately.
- Consensus-backed replication is only part of the story: read freshness, transaction boundaries, and invariant scope determine the actual client contract.
- When Harbor Point needs both transactional correctness and real-time order, the target guarantee is strict serializability, which raises the coordination cost.