Consistency Models

Intro

Consistency models define what value a read is allowed to return relative to writes in a distributed system.
They matter because every replication, partition-tolerance, and caching decision is also a consistency decision.
You think about consistency when selecting storage, designing leader/replica topology, and deciding whether stale reads are acceptable.
In interviews, the important skill is mapping each business invariant to the weakest model that still preserves correctness.

Models

Strong or Linearizable

Sequential

Causal

Eventual

Read-your-writes or Session

Tradeoffs

Model Guarantee Example Use Case Cost
Strong / Linearizable Latest write in real-time order Payments, inventory decrement, distributed lock state Highest latency, lower availability under partition
Sequential One global order preserving per-client order Shared config updates High coordination, weaker real-time guarantee
Causal Preserve cause/effect order Chat threads, collaborative docs Medium complexity, dependency metadata
Session Client sees own writes Profile/settings updates Low-medium cost, session token plumbing
Eventual Converges after writes stop Catalog/cache/reference data Lowest coordination, stale reads expected

Tunable consistency (Cosmos DB)

Azure Cosmos DB sets a default consistency level at the account level.
For the API for NoSQL SDKs, clients and requests can relax reads to weaker levels, but cannot strengthen beyond the account default.

This is a practical tradeoff spectrum: moving from Strong toward Eventual reduces coordination cost and latency while increasing stale-read risk.
During a partition, preserving stronger consistency typically means reduced availability for affected requests, which is the operational lens of CAP theorem.

Pitfalls

Practical decision checklist

Example: Optimistic Concurrency for Read-Your-Writes

ETag-based optimistic concurrency enforces that a write only succeeds if the client's version matches the server's current version — a practical implementation of session consistency for HTTP APIs:

// GET /orders/42 returns ETag: "v3"
// Client stores the ETag and sends it on the next write

// PUT /orders/42 with If-Match: "v3"
// If another writer committed between the GET and PUT, the server returns 412 Precondition Failed
app.MapPut("/orders/{id}", async (int id, OrderUpdate update,
    HttpContext ctx, OrderRepository repo) =>
{
    var etag = ctx.Request.Headers.IfMatch.FirstOrDefault();
    var order = await repo.GetAsync(id);
    if (order is null) return Results.NotFound();

    // Reject if the client's version is stale (another writer committed first)
    if (etag is not null && etag != order.ETag)
        return Results.StatusCode(412);  // Precondition Failed

    order.Apply(update);
    order.ETag = Guid.NewGuid().ToString("N");
    await repo.SaveAsync(order);
    return Results.Ok(order);
});

This pattern implements read-your-writes at the API layer: the client reads the current ETag, includes it on the write, and the server rejects stale writes. The client retries with a fresh GET if it receives 412.

Questions

References


Whats next