shreyansh

Write Conflicts

30-Second Glance

  • Concurrent writes are conflicting writes made without awareness of each other — the central hazard of multi-leader/leaderless setups.
  • Conflict avoidance (route same-key writes to one leader) sidesteps the problem when the workload allows it.
  • Convergence options: Last Write Wins, higher replica-ID wins, value merging (e.g. concat), or explicit conflict records for later resolution.
  • LWW converges but discards concurrent (sometimes even non-concurrent) writes — fine for caches, unsafe for critical data; Cassandra uses LWW only, Riak optionally.
  • Version vectors tell you when writes are actually concurrent; siblings/CRDTs then defer or automate the merge.

Dealing with write conflicts:

Concurrent writes: Conflicting writes that are unaware of each other at the time of writing.

1. Conflict Avoidance

Screenshots/101df6a686a5b030a36730e12c38d945_MD5.jpeg

2. Converging towards a consistent state:

  1. Last Write Wins (LWW)
Screenshots/04235d4cdebff278c622dcd5e79d3634_MD5.jpeg
It's conflict resolution method where each replica stores only the most "recent" value and discards older values. This ensures eventual convergence of replicas to the same value. However, the "recent" value is determined arbitrarily, often using `timestamps`, because concurrent writes don’t have a natural order.
**Advantages**:
- Ensures eventual consistency among replicas.
**Disadvantages**:
- Sacrifices durability by discarding concurrent writes, potentially leading to data loss.
- May even discard non-concurrent writes due to the arbitrary ordering.
**Usage Considerations:**
- Suitable for scenarios where data loss is acceptable, like caching.
- Unsafe for critical data where losing writes is not acceptable.
- Recommended usage in databases like Cassandra involves treating keys as immutable and using unique keys (e.g., UUIDs) to avoid concurrent updates.

**Example Databases:**
- Cassandra supports only LWW for conflict resolution.
- Riak offers LWW as an optional feature.

2. Give each replica a unique ID, and let writes that originated at a higher-numbered replica always take precedence over writes that originated at a lower- numbered replica. This approach also implies data loss. 3. Somehow merge the values together—e.g., order them alphabetically and then concatenate them. 4. Record the conflict in an explicit data structure that preserves all information, and write application code that resolves the conflict at some later time (perhaps by prompting the user), eg. Version Vector.

ed75996f243c8243050de25df7fe0d5c_MD5.webp
  1. Store siblings and have the user decide later to resolve merge conflicts, let's say through Application Layer. (Read more about it in the following article).
  2. The DB automatically merges them for us! This is the premise behind CRDTs. Conflict-Free Replicated Data Types - CRDTs (Read more about it in the following article).

3. When are writes concurrent?

Version Vector:

Version vector in the below example will store the writes (or let's say incremented values after writes from different Leaders). [Counter1 from Leader1, Counter2 from Leader2, Counter3 from Leader3]

Screenshots/9fc374821a5c5a6e872d1cfa0d55394d_MD5.jpeg
Option 1:
Screenshots/05e5f6b01d8f4ca0d8cfef7feb52af88_MD5.jpeg
Option 2:

The DB automatically merges them for us! This is the premise behind CRDTs(Conflict-Free Replicated Data Types - CRDTs!)

Trade-offs

Approach Pros Cons Use when
Conflict avoidance (single writer per key) No conflicts to resolve Restricts routing; loses multi-leader write-anywhere freedom Partitionable workloads with sticky writers
Last Write Wins by timestamp Simple; all replicas converge Arbitrary order; data loss; clock skew can kill non-concurrent writes Caches or immutable/unique keys (UUIDs) where loss is acceptable
Replica-ID precedence Deterministic, no clocks needed Still silently drops the loser's write Toy tie-breaking, never critical data
Merge values / store siblings / CRDTs Preserves information; app or DB merges later App complexity (siblings) or restricted data types (CRDTs) Collaborative or counter-style data worth saving

Interview One-Liners

Q: What counts as a concurrent write? A: Conflicting writes issued without awareness of each other, so neither causally follows the other.

Q: How does Last Write Wins work and what does it cost? A: Every replica keeps only the "most recent" value by timestamp; it converges but discards concurrent writes, risking data loss.

Q: When is LWW acceptable, and who uses it? A: When loss is tolerable like caches, or with immutable unique keys; Cassandra supports only LWW, Riak offers it optionally.

Q: Besides LWW, what convergence tricks does the note list? A: Higher replica-ID wins, merging values (e.g. alphabetical concat), recording explicit conflict structures, storing siblings for app-side resolution, or auto-merge via CRDTs.

Q: How do you know writes were actually concurrent? A: Version vectors — e.g. per-leader counters [c1, c2, c3] — that are mutually non-dominating indicate concurrency.

Q: Siblings vs CRDTs? A: Siblings store all conflicting versions for the application/user to merge later; CRDTs have the DB merge them automatically.