Representative interview topic

How Do You Explain Causal Consistency and Design Verifiable Session Guarantees?

GeneralHard
Offer.cc Editorial TeamPublished Updated

Question

A geo-replicated comment system stores a parent comment and its reply on different replicas. A user must not see the reply and later lose the parent, or read an older version after a successful write. Explain causal consistency versus linearizability and eventual consistency, design session guarantees, and show how to verify that the implementation has no causal inversion.

Prompt and Applicable Roles

A geo-replicated comment system stores a parent comment and its reply on different replicas. A user must not see the reply and later lose the parent, or read an older version after a successful write. Explain causal consistency versus linearizability and eventual consistency, design session guarantees, and show how to verify that the implementation has no causal inversion.

This question fits distributed-systems, backend, infrastructure, and general engineering interviews. It does not require a particular database. State the replica model, replication lag, and the fact that requests carry causal context that can be propagated.

What the Interviewer Is Testing

A strong answer has four layers: define happens-before and distinguish consistency strength; map read-your-writes, monotonic reads, monotonic writes, and writes-follow-reads to a request flow; explain how a replica waits or forwards to satisfy dependencies; and use delayed replication, reordered messages, and failover to prove the properties. It should also say that causal consistency does not create a total order for concurrent writes; conflict resolution remains an application concern.

Questions to Clarify Before Answering

“Causally related” usually comes from a write followed by a read in one client session, a write that read the result of another write, or an explicit parent-child relation in the domain. Concurrent writes without a happens-before edge may appear in different orders at different replicas. Do not define causal consistency as every client seeing one identical order.

Clarify four boundaries: whether context crosses retries and asynchronous queues; whether a replica may remain permanently behind; how stale a read may be; and whether conflicts use LWW, CRDT, or a domain rule. Without these boundaries, the claimed guarantee cannot be tested.

30-Second Answer Framework

“Causal consistency requires causally related writes to be observed in the same causal order, while concurrent writes may appear in different orders. It provides stronger user-visible guarantees than eventual consistency, but it is not linearizability or Spanner’s external consistency; those stronger models also require results to fit one real-time order.

I would propagate a version vector or opaque causal token from the client. Each write sends its known dependencies to a replica and merges the committed version back into the token. A read goes only to a replica that has satisfied the token, or waits or forwards; if it cannot satisfy the contract, it returns an explicitly degraded result. I would inject replication delay, message reordering, retries, and failover, then check that a reply never appears without its parent and a session never loses its own write while measuring wait latency, context size, and fallback rate.”

Step-by-Step Deep Dive

Dependency Context and Session-Guarantee Design

Represent client context as a version vector or opaque causal token. A replica tracks the versions it has applied and checks dependencies before serving a read:

text
context = client.context

write(key, value, context):
  result = replica.write(key, value, dependency=context)
  context = merge(context, result.version)
  return result

read(key, context):
  replica = chooseReplicaSatisfying(context)
  result = replica.readAfter(context)
  context = merge(context, result.context)
  return result

Read-your-writes means a later read is not older than the session’s own write. Monotonic reads mean a session never moves backward. Monotonic writes mean writes from one session are applied in commit order. Writes-follow-reads means a later write carries dependencies observed by an earlier read. If a replica lacks a dependency, it can wait, forward to a replica with a newer safe point, or return a stale result marked as degraded when the product explicitly allows it. The last option cannot still claim the original guarantee.

Concurrent Writes, Failures, and Performance Trade-offs

Causal consistency constrains only derivable ordering. If two users edit the same text concurrently, it does not choose a winner for the application. LWW can lose an update; CRDTs or domain merges can preserve more intent, with metadata and implementation cost.

More precise context can increase dependency wait and tail latency, and version vectors can grow. Sending every request to a primary simplifies the guarantee but sacrifices regional latency and availability. Eventual-consistency replication is cheaper, but it does not automatically provide read-your-writes or monotonic reads. If the business requires commit order to match real-time order, evaluate linearizability or external consistency, accepting more coordination.

Executable Verification Plan

Build a test with a unique causal chain: write the parent comment, read it, write the reply, and read from replicas in different regions. Inject replication delay, a network partition, reordered and duplicated messages, client retries, and primary failover. Record the causal token, observed version, and replica ID for every read.

Assert at least that a request observing a reply can also observe its parent; a successful write is not followed by an older read in the same session; session read versions are monotonic; and concurrent writes may be observed in different orders but eventually converge under the declared conflict rule. Preserve the shortest violating event sequence so you can distinguish a lost token, an incorrect dependency check, and a stale replica watermark.

High-Quality Sample Answer

“I would define the parent-to-reply edge as happens-before. Causal consistency requires every replica to preserve that edge, while two simultaneously created comments may appear in different orders. Linearizability additionally requires one real-time order; eventual consistency only promises convergence after writes stop.

The client maintains a version vector or causal token and propagates it through retries, asynchronous jobs, and service calls. A write sends the token as a dependency and merges its new version on success. A read chooses a replica that has satisfied the token or waits or forwards. This implements read-your-writes, monotonic reads, monotonic writes, and writes-follow-reads, subject to explicit wait and fallback semantics.

I would not claim that causal consistency resolves concurrent conflicts. The same field still needs LWW, a CRDT, or a domain merge. Tests would delay and reorder replication, duplicate requests, and fail over between replicas, checking that a reply never escapes its parent, session versions never go backward, and tail latency, context size, waits, and fallback rates remain within the declared budget.”

Common Mistakes

  • Calling causal consistency a global total order → concurrent writes have no required order → separate happens-before from concurrency.
  • Saying “replicas eventually sync” → that gives no session guarantee → describe tokens, dependency checks, and replica selection.
  • Assuming read-your-writes is a database default → cross-replica routing can return an older version → propagate the write version and check the replica watermark.
  • Dropping context in an asynchronous queue → a reply job loses the parent dependency → carry the token in messages and retry metadata.
  • Claiming LWW solves causal conflicts → LWW may overwrite a concurrent update → make merge policy a separate application decision.
  • Testing only the healthy path → delay, reordering, and failover expose inversions → inject faults and preserve the shortest event sequence.

Follow-Up Questions and Responses

Follow-up 1: When would you choose causal consistency over linearizability?

Choose linearizability or stronger semantics when every client must observe one real-time order and operations must look atomic on one machine. A comment timeline often needs parent-child visibility and session guarantees, so causal consistency can retain more local-read performance. A payment balance must first satisfy its business invariant before choosing the coordination cost.

Follow-up 2: Can a replica return a stale read when it lacks a dependency?

Only if the API labels it as degraded and the caller accepts that contract. If the product promises that seeing a reply implies seeing its parent, a stale read violates the contract; wait, forward, or return a retryable error and include the wait budget in the SLO.

Follow-up 3: Can version vectors grow without bound?

More replicas and clients increase metadata. Token compression, leases, causal stability points, or a bounded participant set can control cost, but each technique must prove that required dependencies are not removed. Measure context size and merge overhead under the expected membership churn.

Follow-up 4: How do you prove the tests cover a real causal inversion?

Record a write ID, dependency token, applied watermark, replica, and read result for every event, then build the happens-before graph. Replay the shortest violating chain and ensure token loss, duplicate delivery, reordering, and failover paths either reproduce the failure or trigger an assertion.

Public sources

Related questions