TL;DR

1. The problem: why can't every replica always agree?

Instagram keeps several copies (replicas) of almost every piece of data — across machines, across availability zones, across regions — so that it survives failures and serves users nearby (see Core Principles). The moment there are two copies, a question appears: when one copy changes, what do readers of the other copy see, and when?

Copies are kept in sync by sending messages over a network. Messages take time (0.5 ms inside a data centre, ~100 ms between continents), and sometimes they don't arrive at all: a switch fails, a fibre is cut, a misconfigured firewall drops traffic, a garbage-collection pause makes a node look dead. Now consider two Instagram scenarios during such a network failure between the US and EU data centres:

The same infrastructure, two opposite right answers. The CAP theorem explains why you must choose, PACELC explains the cost even when nothing is broken, and consistency models give you precise words for what you are choosing.

🧠 Analogy Two branches of a small bank share one ledger, kept in sync by phone. One day the phone line goes dead. A customer walks into branch A and asks to withdraw money. Branch A can either refuse ("I can't confirm your balance with branch B right now — come back later") — that's choosing consistency over availability; or allow it and reconcile when the line is back — choosing availability, at the risk that the customer also withdrew at branch B and is now overdrawn. There is no third option that is both always open and never wrong while the phone is dead. And even on a normal day, calling the other branch before every withdrawal makes customers wait (PACELC's latency cost).

2. The CAP theorem, precisely

The CAP theorem was proposed as a conjecture by Eric Brewer (2000) and proved by Seth Gilbert and Nancy Lynch (2002). It is about a distributed data store with replicated data, and it uses three precise definitions:

C — Consistency

Specifically linearizability: the system behaves as if there were a single copy of the data, and every read returns the value of the most recent completed write (or a later one). Once anyone has seen a new value, nobody may see an older one.

A — Availability

Every request received by a non-failing node must eventually receive a non-error response. Not "most requests", not "the majority side" — every node that is up must answer, without waiting for the partition to heal.

P — Partition tolerance

The system continues to operate even when the network drops or delays an arbitrary number of messages between nodes — i.e., when nodes are split into groups that can't communicate.

The theorem: no distributed system can guarantee all three at once. More usefully: when a partition happens, you must give up either C or A.

2.1 Why it's really "CP or AP", not "pick any two"

The popular phrasing "pick two of three" is misleading. Partitions aren't a feature you can decline; in any system that spans more than one machine, networks will fail. A "CA" system — consistent and available but not partition tolerant — only exists on a single node (or a network that never fails, which doesn't exist). So in practice:

When there is no partition, a well-built system can provide both C and A. CAP only tells you what must give during the failure.

2.2 A partition scenario, step by step

CP choice: refuse rather than be wrong AP choice: answer, reconcile later Alice (US) Bob (EU) Node UShas majority Node EUminority side Alice (US) Bob (EU) Node USaccepts writes Node EUaccepts writes claim @sunsetclaim @sunsetclaim @sunsetclaim ✕ ✕ partition partition ✅ Alice: "@sunset is yours" (US has quorum) ❌ Bob: "Error, try again" (EU can't reach a quorum, so it must not decide) Consistent ✔ · Available ✘ (for Bob) ✅ Alice: "@sunset is yours" ✅ Bob: "@sunset is yours" ⚠️ After healing: two owners → conflict! Available ✔ · Consistent ✘ For usernames Instagram must pick CP; for like counts AP is the better trade.
The same partition, two behaviours. Neither side can know whether the other side has accepted a conflicting write.

The proof is essentially this picture. Suppose a partition separates node US from node EU. A client writes to US; then another client reads from EU. EU has two options: answer with whatever it has (possibly stale — violating C), or wait/refuse until it can talk to US (violating A). Since the partition may last arbitrarily long, there is no way to do both.

2.3 Common misconceptions about CAP

3. Examples of CP and AP systems

SystemUsually classified asWhat happens during a partitionTypical use
ZooKeeper, etcd, ConsulCPMajority side (quorum) keeps serving; minority rejects writes (and, for linearizable reads, reads)Leader election, configuration, locks, service discovery
Google Spanner, CockroachDBCPConsensus (Paxos/Raft) per data range; ranges without a majority become unavailableGlobally consistent transactional data
HBase / BigtableCPEach key range served by one server; if it's unreachable, that range is unavailable until reassignedLarge-scale strongly consistent wide-column data
Single-leader SQL (PostgreSQL/MySQL with replicas)CP-ish for writesWrites only on the leader's side; replicas on the other side can serve stale reads if allowedUsers, accounts, anything needing uniqueness
Cassandra, ScyllaDBAP by default (tunable)Any replica accepts reads/writes at consistency ONE; hinted handoff and repair reconcile later. With QUORUM, the minority side fails requests (more CP-like)High-write, always-on data: posts, likes, messages
Amazon Dynamo (paper), Riak, DynamoDB (default reads)APSloppy quorums, hinted handoff; conflicts resolved by vector clocks/LWWShopping carts, session data, high availability key-value
DNSAPResolvers keep serving cached (possibly stale) records until TTL expiryName resolution (DNS)
CDN edge cachesAPServe stale content if the origin is unreachableMedia delivery (CDN)
Redis replication (async)AP-ishReplicas serve possibly stale data; a failover can lose recent writesCaches, timelines, counters (Caching)

4. PACELC: consistency costs latency even without partitions

Daniel Abadi proposed PACELC (2010, published 2012) to fix CAP's blind spot: partitions are rare, but the trade-off between consistency and latency is paid on every single request.

if (Partition) { choose Availability or Consistency }
else           { choose Latency     or Consistency }
Network partition? YES (P) NO (Else) Availability or Consistency? Latency or Consistency? PA: keep answering(Cassandra, Dynamo) PC: refuse minority(Spanner, etcd) EL: answer locally(async replicas) EC: coordinate first(sync replication)
PACELC: the "else" branch is where your system lives 99.9%+ of the time — and where users feel the latency of strong consistency.

Why does consistency cost latency without partitions? To guarantee a read sees the latest write, either the write must be synchronously copied to other replicas before it's acknowledged, or the read must consult several replicas (or the leader). Both add round trips. Within a data centre that's ~0.5–2 ms; across regions it's ~50–150 ms per round trip. A globally linearizable write from Mumbai with a quorum spanning Virginia and Ireland costs hundreds of milliseconds — a huge price for a like.

SystemPACELC (commonly cited)Meaning
Dynamo, Cassandra, RiakPA/ELFavour availability during partitions and low latency otherwise; consistency is tunable per request
Spanner, VoltDB, HBase/BigtablePC/ECAlways pay for consistency — refuse during partitions, coordinate (consensus) on normal writes
MongoDB (classic configuration)PA/ECAbadi's classification: consistent reads from the primary in normal operation; behaviour during partitions depends on configuration (majority write concern makes it more PC)
Yahoo! PNUTSPC/ELLow-latency reads normally; gives up availability rather than consistency under partitions

Most modern systems are tunable, so treat these labels as defaults, not laws. The useful habit is to ask, for each feature: during a partition, would I rather return an error or stale data? And normally, is the extra latency of coordination worth it?

5. The consistency models spectrum

"Consistent or not" is too coarse. A consistency model is a contract between the data store and its users that says which values a read may return given the history of writes. Models range from strong (easy to reason about, expensive) to weak (cheap and available, harder to reason about).

◀ stronger: more coordination, higher latency, less available weaker: faster, more available ▶ LinearizableSequentialCausalSessionEventual single copy, real timeone global ordercause before effectRYW, monotonic readsconverges eventually claim a usernamechange password messages in a chatin the same order reply never shownbefore its comment I see my own post;counts never go back like counts, feeds,follower counts Instagram example for each model (blue boxes). Each model includes the guarantees of the models to its right.
The consistency spectrum with an Instagram feature that needs each level.

5.1 Linearizable (strong) consistency

Definition: every operation appears to take effect atomically at a single instant between its start and its end, and all clients agree on that order, which respects real time. Equivalently: the system behaves as if there were one copy of the data. If a write completes before a read starts, the read must see that write (or something newer).

Instagram scenario — username uniqueness: Alice's sign-up request claims @sunset and gets "success". From that instant, any other sign-up anywhere in the world must see @sunset as taken. If even one replica could answer "available" after Alice's success, two accounts could get the name.

 time ──────────────────────────────────────────────────────────▶
 Alice:  |── claim @sunset ──| ✔ success
 Bob:                            |── is @sunset free? ──|  must answer "taken"
 Carol:          |──── is @sunset free? ────|            may answer either: it overlaps
                                                         Alice's write (concurrent)

How it's implemented: a single leader for the key (a PostgreSQL primary with a UNIQUE constraint) or a consensus protocol (Raft/Paxos, as in etcd or Spanner). Cost: every write coordinates with a leader/majority; unavailable on the minority side of a partition.

5.2 Sequential consistency

Definition: all clients see all operations in the same single order, and each client's own operations appear in the order it issued them — but that global order need not match real time. (A read may return an older value as long as everyone agrees on the sequence.)

Instagram scenario — DM conversation ordering: in a group chat, Ann sends "Dinner at 8?", then Ben replies "Yes!" and Cat replies "Can't, sorry". All three participants must see the messages in the same order on every device; it doesn't matter if Cat's phone receives the latest message a second later than Ann's. Implementation: a per-conversation sequence number assigned by one owner (the conversation's partition leader), so the total order is per conversation, not global — see Direct Messaging.

5.3 Causal consistency

Definition: operations that are causally related (one could have influenced the other — e.g. you read X then wrote Y) are seen by everyone in that order. Operations that are concurrent (neither knew about the other) may be seen in different orders by different clients.

Instagram scenario — comments and replies: Dan comments "Where is this?" on a photo; the author replies "Lisbon!". The reply was caused by the comment. Under causal consistency, no viewer can ever see "Lisbon!" without "Where is this?". Similarly, if Eve blocks Frank and then posts, Frank must never see that post — the block causally precedes the post. Two unrelated comments by strangers, however, may appear in different orders for different viewers.

 Dan:     write C1 "Where is this?"
 Author:            read C1 ──▶ write C2 "Lisbon!"      (C1 → C2: causal)
 Viewer X sees:  C1, C2            ✔
 Viewer Y sees:  C2 only           ✘ forbidden under causal consistency
 Viewer Z sees:  nothing yet       ✔ allowed (just not caught up)

Causal consistency is the strongest model that remains available during partitions (it can be served from local replicas), which makes it attractive for geo-distributed systems. Implementation: track dependencies (version vectors, or "this write depends on version v of that item") and delay making a write visible until its dependencies are visible.

5.4 Session guarantees: read-your-writes, monotonic reads, monotonic writes

These are weaker, per-client guarantees that fix the most user-visible anomalies of eventual consistency cheaply:

GuaranteeDefinitionInstagram anomaly it preventsTypical technique
Read-your-writes (read-after-write)A client always sees its own previous writesYou post a photo, pull to refresh your profile, and it's not there (your read hit a lagging replica)Read from the leader for a short window after writing; or pass the write's version and wait for a replica that has it
Monotonic readsOnce a client has seen a value, it never later sees an older oneA like count shows 1,204, then 1,198 on refresh, then 1,205 (different replicas)Pin a user's session to one replica; or carry the last-seen version
Monotonic writesA client's writes are applied in the order it issued themYou change your bio twice; the first edit overwrites the secondPer-client sequence numbers; route a user's writes to one leader
Writes-follow-readsA write made after reading X is ordered after XYour reply appears in a replica that doesn't yet have the comment you replied toAttach dependency versions to writes (a slice of causal consistency)

5.5 Eventual consistency

Definition: if no new writes are made to an item, all replicas will eventually return the same value. No promise about when, and no promise about what you see in the meantime. In healthy systems "eventually" usually means milliseconds to seconds.

Instagram scenarios: your friend's new post appears in your feed a few seconds after it was published (asynchronous fan-out through Kafka); a post's like count lags by a second; a celebrity's follower count is approximate; a new account becomes searchable after the indexer catches up. None of these hurt users, and all of them would be expensive to make strongly consistent at Instagram's write rates.

A stronger variant, strong eventual consistency, adds: any two replicas that have received the same set of updates are in the same state — no matter the order received. That's what CRDTs provide (section 8.3).

6. Quorums: tuning consistency with R + W > N

Leaderless stores like Cassandra and Dynamo-style systems let you tune consistency per request with quorums. Each key is stored on N replicas. A write is acknowledged once W replicas confirm it; a read queries R replicas and returns the newest version among their answers.

If R + W > N, every read set overlaps every write set in at least one replica,
so a read always contacts at least one replica holding the latest acknowledged write.
N = 3, W = 2, R = 2 → R + W = 4 > 3: read and write sets must overlap Replica Alikes = 1,204 Replica Blikes = 1,204 Replica Clikes = 1,203 write set (W=2): A, B read set (R=2): B, C B is in both sets → the read sees 1,204 (newest version wins); C is repaired in the background (read repair).
Quorum overlap. C missed the write (it was slow or briefly down) but the read still returns the latest value.
Configuration (N = 3)R + W > N?BehaviourGood for
W = 1, R = 1 (Cassandra ONE)No (2)Fastest, most available; reads may be staleLike events, view counters, analytics
W = 2, R = 2 (QUORUM/QUORUM)Yes (4)Reads see latest acknowledged write (with caveats below); tolerates 1 replica downPost metadata, comments, DM messages
W = 3, R = 1 (ALL / ONE)Yes (4)Fast reads; writes fail if any replica is downRarely-written, read-heavy data
W = 1, R = 3 (ONE / ALL)Yes (4)Fast writes; reads fail if any replica is downRarely used

Across regions, Cassandra offers LOCAL_QUORUM (majority within the local data centre — low latency, PA/EL behaviour across regions) vs EACH_QUORUM (majority in every data centre — consistent across regions, but pays cross-region latency and fails if a region is cut off).

⚠️ Quorums are not automatically linearizable R + W > N is necessary but not sufficient for strong consistency. Edge cases: sloppy quorums (writes accepted by stand-in nodes during failures, so the overlap guarantee breaks), concurrent writes resolved by last-write-wins with skewed clocks (a "newer" write can silently lose), a write that failed on some replicas but succeeded on others (not rolled back), and reads racing with in-progress writes. Truly linearizable operations need consensus — e.g. Cassandra's lightweight transactions (Paxos-based compare-and-set) for "insert username if not exists". See Replication for the full mechanics.

7. ACID vs BASE

Two philosophies for data stores, often contrasted:

ACID (traditional relational transactions)BASE (many NoSQL / AP systems)
Stands forAtomicity (all or nothing), Consistency (invariants preserved), Isolation (concurrent transactions don't interfere), Durability (committed data survives crashes)Basically Available, Soft state (state may change without input as replicas converge), Eventual consistency
PriorityCorrectness of every transactionAvailability and scale; correctness converges over time
ScalingEasiest on one node; distributed ACID needs consensus/2PC (costly)Partition and replicate freely
AnomaliesPrevented (to the chosen isolation level)Stale reads, conflicts — application must tolerate or resolve
ExamplesPostgreSQL, MySQL, Spanner, CockroachDBCassandra, DynamoDB (default), Riak, CouchDB
Instagram dataUsers, usernames, credentials, account settingsPosts, likes, comments, timelines, counters, messages

Note that isolation (the I in ACID) has its own spectrum: read committed → repeatable read / snapshot isolation → serializable. Many databases default to weaker levels than serializable for performance, which allows anomalies like lost updates or write skew — a reminder that "ACID" is not a binary label. (Details in Databases.)

8. Conflict resolution: when replicas disagree

In AP (and multi-leader) systems, two replicas can accept concurrent writes to the same item. After the partition heals, the system must decide the final value. Three main approaches:

8.1 Last-write-wins (LWW)

Attach a timestamp to every write; when versions conflict, keep the one with the highest timestamp and discard the rest. Simple, and the default in Cassandra (per column).

Replica US: bio = "Photographer 📷"   ts = 10:00:00.120
Replica EU: bio = "Traveller ✈️"       ts = 10:00:00.115
After merge → "Photographer 📷"  (EU's write is silently discarded)

Problems: concurrent writes are lost, not merged; and clocks on different machines drift — if the EU server's clock is 50 ms ahead, its earlier write wins. LWW is fine when losing a concurrent write is acceptable (a profile bio edited from two devices at the same instant) or when writes are naturally unique (each like is its own row keyed by (post_id, user_id), so there's nothing to overwrite).

8.2 Vector clocks (version vectors)

A vector clock stores, per item, a counter for each replica that has modified it. Comparing two vectors tells you whether one version happened before the other or whether they are concurrent (a true conflict).

 start:       bio v = {US:1}                          "Photographer"
 US updates:  {US:2}          "Photographer 📷"
 EU updates (concurrently, from {US:1}):  {US:1, EU:1}  "Traveller ✈️"

 compare {US:2} vs {US:1, EU:1}:
   US: 2 > 1   but   EU: 0 < 1   → neither dominates → CONCURRENT → conflict!
   → keep both "siblings" and let the application (or user) merge them

 compare {US:2, EU:1} vs {US:1, EU:1}:
   every entry ≥  → the first is strictly newer → safe to discard the second

Vector clocks never lose a concurrent write silently, but they push merge logic to the application and add metadata per item. The original Amazon Dynamo used them (for shopping carts, merging by union — which famously could resurrect deleted items).

8.3 CRDTs (Conflict-free Replicated Data Types)

CRDTs are data structures designed so that concurrent updates can always be merged automatically and deterministically: the merge is commutative, associative and idempotent, so replicas that have seen the same updates converge to the same state regardless of order (strong eventual consistency).

# G-Counter for a post's view count, replicated in two regions
US = {"US": 1000, "EU": 0}       # US has counted 1,000 views locally
EU = {"US": 0,    "EU": 500}     # EU has counted 500 views locally

merge(a, b) = {r: max(a[r], b[r]) for r in a | b}
merge(US, EU) = {"US": 1000, "EU": 500}   → value = 1,500   (no lost increments,
                                             and merging twice changes nothing)

Redis Enterprise (active-active), Riak and Azure Cosmos DB offer CRDT-based types. The trade-off: only certain operations fit the CRDT mould (you can't enforce "username unique" with a CRDT — uniqueness is inherently a coordination problem), and metadata can grow.

9. Practical techniques: getting "consistent enough" cheaply

Most real systems run on eventually consistent replicas and add targeted techniques where users would notice anomalies.

9.1 Read-your-writes by reading from the leader after a write

With leader–follower replication, followers lag the leader by milliseconds to seconds. To make sure a user sees their own changes:

def update_profile(user_id, fields):
    leader_db.update(user_id, fields)
    session.set("recent_write_until", now() + 10s)      # remember this user just wrote

def get_profile(viewer_id, profile_id):
    # the author sees their own profile from the leader for a short window;
    # everyone else (and the author after the window) reads from a nearby replica
    if viewer_id == profile_id and now() < session.get("recent_write_until", 0):
        return leader_db.get(profile_id)
    return replica_db.get(profile_id)

Variations:

9.2 Monotonic reads via stickiness

Route a given user's reads to the same replica (hash the user ID to a replica) so they never "go back in time" by bouncing between replicas with different lag. If that replica fails, re-pinning may cause one backwards step — acceptable for counts.

9.3 Strong consistency only where it's needed

9.4 Bounded staleness and invalidation

Caches are another source of staleness. Use short TTLs for data that changes, explicit invalidation on writes (delete the cache key after updating the DB), and versioned keys for immutable data (as with CDN URLs). Public papers from Facebook describe techniques such as leases in memcache to prevent stale sets and thundering herds — see Caching.

10. How Instagram chooses consistency per feature

This table is the heart of the lesson — the answer interviewers want when they ask "what consistency does your design provide?"

FeatureConsistency modelMechanism in the diagramJustification
Username uniquenessLinearizable (CP)User DB (PostgreSQL) primary with UNIQUE index on the shard owning the username (or a dedicated username→user_id table); sign-up fails rather than duplicating during failoverDuplicates are a correctness bug; sign-ups are rare (~tens per second), so the latency/availability cost is negligible
Authentication, password change, session revocationStrong for writes; revocations propagate fastUser/Auth Service on the PostgreSQL primary; short-lived access tokens + server-side revocation list checked at the API GatewaySecurity: a stolen session must stop working everywhere promptly
Privacy settings & blocksRead-your-writes + fast propagation; fail closedWritten to the primary; checked at read time on feed/profile/comments, not only at fan-out timeLeaking a post to a blocked user is harmful; better to hide content when unsure
Likes countEventual; approximate OKLike rows in Cassandra (idempotent per user); counts aggregated asynchronously via Kafka into Redis counters~58K likes/s; hot posts get millions of likes; nobody notices if "1.2M" lags by a second
"Did I like this?"Read-your-writesOptimistic UI on the client + read from the user's own like recordThe heart must not flicker back to grey after you tap it
Home feedEventual (seconds); causal where cheapKafka → Fan-out Workers → Redis timelines; hydration from cachesFreshness of seconds is invisible; strong consistency would require synchronous fan-out to hundreds of followers
Your own new post on your profileRead-your-writesUpload Service writes metadata synchronously (quorum) and updates the author's profile cache directly; client shows it optimistically"I posted and it's not there" looks like a bug
Follower / following countsEventual; approximate for large accountsGraph store edges are the truth; counts maintained asynchronouslyCelebrity counts change thousands of times per minute; "512M" needn't be exact
Follow / unfollow edge itselfRead-your-writes for the actorWrite to Graph store; actor's view served from the primary/fresh cacheAfter tapping "Follow", the button must stay "Following"
DM orderingTotal order per conversation (sequential within a chat); at-least-once delivery + dedupeMessages Store partitioned by conversation_id; per-conversation sequence numbers; client message IDs for idempotencyOut-of-order messages change meaning; duplicates are confusing
Comments and repliesCausal where possible; eventual otherwiseReplies reference parent comment ID; clients/servers hide replies whose parent isn't loaded yetA reply without its parent is confusing; strict global order isn't needed
StoriesEventual; expiry enforced at read timeStories metadata with TTL; tray built asynchronously; reads filter expires_at < nowA story appearing a second late is fine; showing an expired story is not
Search indexEventual (seconds–minutes)Kafka → Search Indexer → ElasticsearchIndexing synchronously would slow every write
📸 In Instagram (and Meta) Public engineering material gives a good picture of these trade-offs at Meta scale. Facebook's TAO paper (USENIX ATC 2013), describing the store for the social graph, explains that TAO favours availability and performance: it is eventually consistent across regions, provides read-after-write consistency within a single cache tier, and lets specific reads be marked as critical so they go to the primary region. The "Scaling Memcache at Facebook" paper (NSDI 2013) describes leases to avoid stale cache sets and remote markers to reduce the chance a user reads stale data from a replica region right after writing — a read-your-writes technique. Instagram's own talks describe PostgreSQL (single-leader per shard, strong constraints) for core relational data and Cassandra (tunable, highly available) for high-volume data such as feeds and activity. Exactly the per-feature split in the table above.
Tap "Like"heart red instantly
→optimistic UI
Like serviceidempotent write
→quorum
Cassandralike row
→event
Kafka
→~seconds
Redis countereventually 1,205

11. Trade-offs & common pitfalls

✅ Strong consistency (CP / EC)

  • Easy to reason about: behaves like one copy
  • No conflicts, no anomalies, no merge logic
  • Required for uniqueness, ownership, money, security

✅ Weak/eventual consistency (AP / EL)

  • Low latency: answer from the nearest replica
  • Stays up during partitions and regional outages
  • Scales writes across regions

⚠️ Costs of strong consistency

  • Coordination latency on every write (cross-region: 100+ ms)
  • Unavailable on the minority side of a partition
  • Leader/consensus bottlenecks; lower write throughput

⚠️ Costs of eventual consistency

  • Stale reads, anomalies users can notice
  • Conflict resolution logic (LWW loses data; vector clocks push merges to apps)
  • Harder testing and debugging

Common pitfalls

12. Real-world technologies

TechnologyConsistency offeredWhen to use it
PostgreSQL / MySQL (single leader + replicas)Strong on the leader (ACID); replicas are eventually consistent (async) or synchronous if configuredUniqueness, transactions, relational data (Instagram users)
etcd, ZooKeeper, ConsulLinearizable (Raft / Zab consensus)Leader election, locks, configuration, small critical metadata
Google Spanner, CockroachDB, YugabyteDBLinearizable / serializable distributed transactionsGlobal strongly consistent data; willing to pay coordination latency
Cassandra, ScyllaDBTunable per query (ONE, QUORUM, LOCAL_QUORUM, ALL); LWW; lightweight transactions (Paxos) for CASHigh-volume, always-on writes (posts, likes, messages)
Amazon DynamoDBEventually consistent reads by default; strongly consistent reads optional (single region); transactions; global tables use LWW across regionsManaged key-value at scale
Riak, Redis Enterprise active-active, Azure Cosmos DBCRDTs / multi-region conflict resolution; Cosmos DB offers five levels (strong, bounded staleness, session, consistent prefix, eventual)Multi-region writes needing automatic merges
KafkaTotal order per partition; replicated log with configurable acksOrdering per key (e.g. per conversation) and durable event streams
Redis (async replication)Eventual; failover may lose recent writesCaches, counters, timelines — derived, rebuildable data

13. Interview corner

Explain the CAP theorem precisely.

For a replicated data store, you can't simultaneously guarantee Consistency (linearizability — every read sees the latest completed write, as if there were one copy), Availability (every request to a non-failed node gets a non-error response) and Partition tolerance (correct operation despite arbitrary message loss between nodes). Since networks do partition, the practical meaning is: during a partition, each operation must either be refused/delayed on the side that can't coordinate (CP) or answered with possibly stale or conflicting data (AP). Without a partition, you can have both — but you pay latency for consistency, which is what PACELC adds.

Is Instagram CP or AP?

Neither as a whole — it's chosen per feature. Username registration, authentication and privacy-critical writes are CP: they go through a single leader with constraints and fail rather than risk inconsistency. Feeds, likes, view and follower counts, search and stories are AP/eventually consistent: they keep working from local replicas during failures and converge within seconds. DMs need per-conversation ordering, implemented by partitioning messages by conversation and assigning sequence numbers at one owner.

What is PACELC and why does it matter more day-to-day than CAP?

PACELC: if Partitioned, choose Availability or Consistency; Else choose Latency or Consistency. Partitions are rare, but every request pays the "else" trade-off: strong consistency requires synchronous replication or multi-replica reads — extra round trips, 100+ ms across regions. For Instagram's likes, paying cross-region latency on every tap would be absurd (EL); for username claims it's fine because they're rare and correctness matters (EC).

A user updates their bio and immediately sees the old one. Why, and how do you fix it?

The write went to the leader but the read was served by a follower replica (or a cache) that hasn't caught up — a read-your-writes violation under asynchronous replication. Fixes: route the user's reads of their own profile to the leader for a short window after a write; or return the write's log position and only read from replicas past it; invalidate/update the cache entry on write; and update the UI optimistically on the client.

With N = 3, which R and W would you choose for Instagram comments, and why?

QUORUM writes and reads (W = 2, R = 2, R + W = 4 > 3) within the local region (LOCAL_QUORUM): a comment is visible to subsequent quorum reads, the system tolerates one replica failure per region, and latency stays local. Cross-region replication is asynchronous, so a viewer in another region may see the comment a moment later — acceptable. For like events I'd use W = 1 since counts are aggregated asynchronously anyway.

How would you resolve conflicting writes to a post's like count in an active-active multi-region setup?

Don't store the count as a single overwritten value — LWW would lose increments. Either store each like as its own idempotent record keyed by (post_id, user_id) and derive the count by aggregation, or use a CRDT counter (PN-counter: per-region increment and decrement counters, merged by element-wise max and summed). Both converge without coordination and never lose a like. Uniqueness of "one like per user" comes from the record key, not from coordination.

What's the difference between linearizability and serializability?

Linearizability is a recency guarantee on single objects/operations: each operation appears to happen instantaneously at some point between its invocation and response, respecting real time. Serializability is an isolation guarantee for multi-object transactions: the result equals some serial order of the transactions, which need not match real time. "Strict serializability" combines both (Spanner provides it). CAP's C is linearizability; ACID's I at its strongest is serializability.

Why can't you implement username uniqueness with an AP store and a CRDT?

Uniqueness is a global invariant that requires knowing that nobody else claimed the name concurrently — inherently a coordination problem. An AP store lets both sides of a partition accept "@sunset", and CRDTs can only merge, not reject, so you'd end up with two owners. You need a single authority or consensus (a leader with a UNIQUE constraint, or a Paxos/Raft compare-and-set) and must accept that claims fail when that authority is unreachable.

14. Check your understanding

During a partition, a CP store's minority-side node receives a read. What does it do?

It returns an error or blocks/times out (for linearizable reads), because it can't be sure it has the latest value. The majority side keeps serving normally.

Numeric: N = 5. Which of these guarantee read/write overlap: (a) W=3,R=3 (b) W=2,R=3 (c) W=5,R=1 (d) W=1,R=4?

Overlap requires R + W > 5. (a) 6 ✔ (b) 5 ✘ (c) 6 ✔ (d) 5 ✘.

Numeric: N = 3, W = 2, R = 2. How many replicas can be down while reads and writes still succeed?

One. Both need 2 of 3 replicas. With two down, neither a write quorum nor a read quorum can be formed.

Which consistency model is violated: you see a reply "Lisbon!" but not the comment "Where is this?" it replies to?

Causal consistency — the reply causally depends on the comment, so it must not be visible without it.

Which guarantee is violated: a like count shows 1,204, then 1,198 after refresh?

Monotonic reads — the second read came from a replica that was further behind. Fix by pinning the user to one replica or carrying the last-seen version.

Vector clocks: version X = {US:3, EU:1}, version Y = {US:2, EU:2}. Which is newer?

Neither: US 3 > 2 but EU 1 < 2, so they are concurrent — a genuine conflict that must be merged (or resolved by policy).

Scenario: you use LWW for a profile field and the EU server's clock runs 200 ms fast. What can go wrong?

An EU write made up to 200 ms before a US write can still carry a later timestamp and win, so the newer US update is silently discarded. LWW correctness depends on clock synchronisation; it also loses all but one of any truly concurrent writes.

G-Counter: replica A = {A:7, B:2}, replica B = {A:5, B:4}. What is the merged state and value?

Element-wise max: {A:7, B:4} → value 11. Merging again (or in the other order) gives the same result — that's what makes it conflict-free.

🎯 Key takeaways

Related lessons