NO SQL Lesson 9 – Consistency Models | Dataplexa
NoSQL Fundamentals · Lesson 9

Consistency Models

Two users open the same Google Doc at the same moment. User A types a sentence. User B sees it appear within milliseconds — not after a page refresh, not after a delay. Now imagine a bank: User A transfers £500. The moment that transaction commits, every ATM, every app, every branch in the world must show the updated balance — instantly, no exceptions. These two systems make completely different promises about when data becomes visible. Those promises have a name: consistency models. And choosing the wrong one for your system can cost you data, users, or money.

What a Consistency Model Actually Is

A consistency model is a contract between your database and your application. It answers one question: after I write data, when is it guaranteed to be visible — and to whom?

In a single-server world this is trivial — you write, it's saved, anyone who reads gets it. But the moment you have multiple nodes, multiple data centres, or millions of concurrent users, the answer becomes nuanced. Data has to travel across networks, replicate across servers, and coordinate across processes — and that takes time.

The core tension — visualised:

Strong Consistency

Every read gets the latest write. Always.

Eventual Consistency

Reads converge to latest. Eventually.

← Higher latency, lower throughput Higher throughput, lower latency →

Model 1 — Strong Consistency

With strong consistency, after a write completes, every subsequent read — from any node, any server, any region — will return that new value. No stale data. No exceptions. The system behaves as if there is only one copy of the data.

Real-world analogy:

Imagine a whiteboard in a conference room. When someone writes on it, everyone in the room sees it instantly — there's one physical board. Strong consistency works the same way: one authoritative truth, everyone sees it the moment it changes.

The scenario: You're at a bank. You deposit £1,000 at the ATM. You walk 10 steps to the counter and ask the teller your balance. Strong consistency guarantees the teller sees your deposit — even though you made it 10 seconds ago on a different system. Here's how MongoDB enforces this with read and write concerns:

// Strong consistency in MongoDB
// Write with majority concern — confirmed on most nodes
await db.collection('accounts').updateOne(
  { user_id: 'u_441' },
  { $inc: { balance: 1000 } },
  { writeConcern: { w: 'majority' } }  // wait for majority to confirm
)
w: 'majority'

The write doesn't return success until more than half the replica set nodes have saved it. Slower — but guaranteed. If the primary node dies the next millisecond, the data is still safe on the majority nodes.

$inc: {"{ balance: 1000 }"}

$inc atomically increments a field by the given value. This is safer than read-then-write: you're not reading the balance, adding 1000, then writing it back (race condition risk). You're telling MongoDB "add 1000 to whatever the current value is" in a single atomic operation.

// Read with linearizable concern — guaranteed to see the latest write
const account = await db.collection('accounts').findOne(
  { user_id: 'u_441' },
  { readConcern: { level: 'linearizable' } }
)
console.log(`Balance: £${account.balance}`)
Balance: £1000

-- Read confirmed against majority of nodes
-- Guaranteed to reflect all writes that completed before this read
-- Latency: ~12ms (vs ~2ms for eventual consistency)
-- Use for: financial balances, inventory counts, medical records

What just happened:

readConcern: linearizable — MongoDB contacts the majority of nodes to confirm it's reading from the current primary before returning the result. This prevents a stale read from a node that hasn't caught up yet. The read is slower — but it's guaranteed to be the latest value.

The cost: 12ms vs 2ms. That's 6x slower. For a bank balance — absolutely worth it. For a social media like counter — complete overkill.

Model 2 — Eventual Consistency

With eventual consistency, after a write, different nodes may return different values for a short window — but given enough time with no new writes, all nodes will converge to the same value. The key word is eventually — which in practice usually means milliseconds to seconds, not hours.

Real-world analogy:

Think of a news website. A journalist publishes an article. Some readers see it immediately. Others, on a cached server in a different region, see it 30 seconds later. Eventually everyone sees the new article. The brief window of inconsistency doesn't hurt anyone — and the system served millions of readers with no bottleneck.

The scenario: You're running a social platform. A user posts a status update. It should propagate to all 3 regional nodes — but you don't want the write to wait for all of them. You want to confirm immediately and let the sync happen in the background:

from cassandra.cluster import Cluster
from cassandra import ConsistencyLevel
from cassandra.query import SimpleStatement

session = Cluster(['us-east','eu-west','ap-south']).connect('social')

Cluster(['us-east','eu-west','ap-south']) — three Cassandra nodes in three regions. Writes go to all three eventually. The driver picks the closest node for each request automatically.

# Write with ONE consistency — only 1 node needs to confirm
post = SimpleStatement(
  "INSERT INTO posts (user_id, post_id, body, ts) VALUES (%s, %s, %s, %s)",
  consistency_level=ConsistencyLevel.ONE
)
session.execute(post, ('u_8821', uuid4(), 'Just shipped v3!', datetime.now()))
-- Write acknowledged by us-east in 1.3ms
-- eu-west and ap-south will sync within ~80ms

-- If a user in London reads right now (eu-west):
--   Might see: post not yet visible      (eu-west hasn't synced)
-- If same user reads 200ms later:
--   Will see: "Just shipped v3!"         (synced — eventually consistent)

-- Write latency: 1.3ms
-- Strong consistency equivalent: ~45ms

Breaking it down:

ConsistencyLevel.ONE

One node confirms — done. The write returns in 1.3ms. Cassandra's gossip protocol handles syncing the other two nodes in the background. You traded perfect consistency for 35x better write latency.

Post invisible for ~80ms in eu-west

This is the eventual consistency window. For a social post, this is completely acceptable — nobody is harmed by a post being 80ms late to appear. For a bank balance, this would be catastrophic. Context is everything.

Model 3 — Read-Your-Writes Consistency

Read-your-writes is a middle ground that solves a specific and very common problem: you write something, then immediately read it back — and see the old value. This feels like a bug even when the system is working as designed.

Real-world analogy:

You update your profile photo on a social network. You refresh the page — and see your old photo. Five minutes later it shows the new one. This is eventual consistency without read-your-writes. It feels broken even though it technically isn't. Read-your-writes guarantees: you always see your own writes immediately, even if others might see them slightly later.

The scenario: A user updates their display name. They expect to see the new name immediately everywhere. Here's how DynamoDB implements read-your-writes:

import boto3

dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table = dynamodb.Table('users')

# Write the updated display name
table.update_item(
  Key={ 'user_id': 'u_4421' },
  UpdateExpression='SET display_name = :name',
  ExpressionAttributeValues={ ':name': 'Priya S.' }
)

UpdateExpression — DynamoDB's way of modifying specific fields without overwriting the entire item. SET display_name = :name updates only that field. The colon prefix (:name) marks it as an expression attribute value — prevents conflicts with reserved words.

# Read back immediately — with strongly consistent read
# This guarantees the user sees THEIR OWN latest write
response = table.get_item(
  Key={ 'user_id': 'u_4421' },
  ConsistentRead=True   # strongly consistent — reads from primary
)
print(response['Item']['display_name'])
Priya S.

-- ConsistentRead=True reads from the primary node
-- Guarantees this user sees their own update immediately
-- Other users reading via eventually consistent path:
--   May see "Priya" for up to 100ms, then "Priya S."
--   That's acceptable — they didn't make the change

The key insight:

ConsistentRead=True — DynamoDB reads directly from the primary node instead of a potentially-stale replica. The write just happened — the primary has it. Other users reading from replicas might see a brief delay, but the person who made the change sees it instantly.

When to use this pattern: Profile updates, settings changes, any "I just changed this, show me the result" flow. The user who made the change needs to see it. Everyone else can tolerate a brief lag.

Model 4 — Causal Consistency

Causal consistency goes one step further than read-your-writes. It guarantees that operations that are causally related — one event logically depends on another — are seen in the right order by everyone.

Real-world analogy:

You post a question in a forum: "Anyone know how to fix this bug?" Your colleague replies "Yes, use this fix." Without causal consistency, some users might see the reply before the original question — the answer appears before the question it answers. Causal consistency ensures that if you see the reply, you also see the question it was replying to.

Causal consistency in practice — MongoDB sessions:

// MongoDB causal consistency session
// Operations in this session are causally ordered
const session = client.startSession({ causalConsistency: true })

// Write: post a comment
await db.collection('comments').insertOne(
  { post_id: 'p_99', body: 'Great article!', user: 'Priya' },
  { session }
)

// Read: get all comments on this post
// Guaranteed to include the comment just written — causal order preserved
const comments = await db.collection('comments')
  .find({ post_id: 'p_99' }, { session })
  .toArray()

causalConsistency: true — MongoDB tracks a cluster time token for this session. Each write returns a token. Each subsequent read sends that token — MongoDB guarantees the read happens after the write that produced that token.

Why this matters: Without causal consistency, the read might be routed to a replica that hasn't received the write yet. Your comment would vanish from the page immediately after posting — a confusing and trust-destroying user experience.

The Full Consistency Spectrum

Model Guarantee Latency Cost Use When Example
Strong (Linearizable) Every read sees the latest write globally High — 10–50ms Wrong data = real harm Bank balances, stock levels
Causal Related operations seen in correct order Medium — 5–15ms Order of events matters Comments, replies, chat
Read-Your-Writes You always see your own writes Medium — 3–10ms UX feels broken without it Profile updates, settings
Eventual All nodes converge — eventually Low — 1–3ms Stale data causes no harm Like counts, view counters, feeds

The Same System, Different Models for Different Data

The real skill is not picking one consistency model for your whole system. It's picking the right model for each piece of data based on the actual consequences of staleness.

A real e-commerce platform — 4 data types, 4 consistency choices:

1
Inventory count — last 3 items in stock Strong Consistency

If two users see "3 items left" simultaneously and both buy 2, you oversell. Wrong data here = real fulfilment cost, angry customers. No tolerance for staleness.

2
Order status updates Read-Your-Writes

You place an order, then immediately check "My Orders." You must see it. Other users seeing a 200ms delay on each other's orders — doesn't matter. Your own write must be visible to you instantly.

3
Product review threads Causal Consistency

A user asks "Does this fit a size 8?" Someone replies "Yes, runs true to size." The reply must always appear after the question — causal order. Seeing an answer before the question breaks the conversation thread.

4
Product view counter ("4,821 people viewed this") Eventual Consistency

Showing 4,820 vs 4,821 for 100ms — completely harmless. Running strong consistency writes for every single page view would be a catastrophic waste of database resources. Eventual is the obvious choice.

Teacher's Note

The engineers who get consistency right are the ones who ask one question before choosing a model: "What is the actual consequence if two users see different values for this field for the next 200 milliseconds?" If the answer is "a financial loss, an oversell, or a safety issue" — you need strong consistency. If the answer is "a view count is slightly off" — eventual is fine and you'll save enormous resources by using it. Consistency is not a database setting. It's a business decision.

Practice Questions — You're the Engineer

Scenario:

A YouTube-style platform counts video views. A video gets 50,000 views per minute at peak. The view counter displayed to users can be a few seconds behind the real number — nobody is harmed if it shows 1,482,100 instead of 1,482,147 for a moment. Maximum write throughput is the priority. Which consistency model should you use?


Scenario:

A user updates their profile bio and clicks Save. The page reloads and shows the old bio — their change seems to have disappeared. They update it again. Same issue. After 5 seconds, both updates appear. This is a classic distributed systems UX bug. Which consistency model, if applied to the user's own reads, would have prevented this?


Scenario:

A hospital system records medication doses administered to patients. A nurse logs a dose on one terminal. A doctor checks the patient record on another terminal 30 seconds later and needs to see that dose — not seeing it could result in a double dose being administered. Which consistency model is non-negotiable here?


Quiz — Which Model Fits?

Scenario:

Users in your chat app report seeing reply messages appear before the original message they were responding to. Both messages are visible within 2 seconds, but the order is wrong. Which consistency model, if implemented correctly, would guarantee replies always appear after the messages they reply to?

Scenario:

Black Friday. A limited-edition trainer has 1 pair left in stock. 200 users click Buy at the same second. Your database uses eventual consistency for inventory counts. What is the likely outcome — and what consistency model would have prevented it?

Scenario:

You're designing a checkout flow. Step 1: charge the customer's card and write a payment record — this must be 100% consistent, no partial writes. Step 2: show the user an order confirmation page — they must see their order immediately after placing it. What is the right consistency strategy across these two steps?

Up Next · Lesson 10

NoSQL Use Cases

Real systems, real companies, real decisions — the exact scenarios where NoSQL is the obvious right choice and the ones where engineers regret it later.