The Pattern
WRITE: ack immediately after CACHE accepts; db update ASYNC
app ──write──► [ cache ] ──ack──► caller (fast!)
│
└── buffered queue ──► batch flush ──► [ db ]
(every N sec / M entries)
READS: always served from cache → fast AND fresh
aka WRITE-BACK. the queue between cache and storage is
the entire design problem.
What It Buys
✓ write latency = cache speed alone (~1ms, no db hop)
✓ write BURSTS absorbed by buffer; db sees steady batches
(queue-based load leveling, built into your writes)
✓ batching cuts db load: 1000 updates → few bulk upserts
✓ db outages tolerated briefly (writes queue while it's down)
classic homes: like counters, view counts, presence hearts,
game score updates — hot counters that would melt a row
lock if written synchronously per event.
The Price: Loss Window
cache node dies before flush → those writes are GONE.
uncommitted window = flush interval × failure probability
engineering the window down:
- short flush intervals (1–5s typical)
- replicate the buffer itself (redis replication/AOF)
- journal writes to disk BEFORE ack (WAL-in-cache)
- accept loss for THIS data class (likes ≠ payments)
decision rule: "is losing ≤5s of these writes acceptable?"
NO → write-through/aside instead. this pattern is only for
data whose loss is annoying, never catastrophic.
Consistency Complications
- reads from OTHER paths hit the DB and see STALE data
until flush → cross-system read-your-writes breaks
- concurrent updates to same key need merge semantics
(last-write-wins? increment? CRDT-ish?)
- ordering: buffer must preserve per-key order
or final state may be wrong even without loss
document which external readers see stale data and how long;
surprise staleness is how write-behind deployments die politically.
Flush Design
| Mechanism | Behavior |
|---|---|
| Interval timer | Flush every T seconds — predictable lag |
| Size threshold | Flush at M pending — bounds memory |
| Hybrid | Whichever first — standard choice |
| Per-key coalescing | Collapse repeated writes; flush last value |
| Incremental ops | Ship INCR deltas instead of absolute values |
Coalescing matters enormously for counters: 500 likes in the interval become ONE +500 statement.
When It Fits
✓ high-rate mutable counters/stats with loss tolerance
✓ bursty writes against a fixed-capacity store
✗ money, inventory, anything audited
✗ when other systems read the db expecting freshness
often implemented NOT as whole-database strategy but as a
targeted counter-service: redis + periodic flush job beside
an otherwise conventional stack.
Interview Framing
“Count video views at 100k/s” is THE trigger question. Scored shape: write-behind with INCR in Redis, hybrid flush (2s/10k), coalescing math (“db sees ~1 write/sec per video”), explicit loss-window acceptance, and the boundary sentence — “payment writes stay synchronous.” That last line is what separates pattern knowledge from judgment.
Premium Content
Unlock Write-Behind and all premium lessons with a subscription.
All premium lessons
Ad-free experience
Priority support
From ₹199.99/year — See plans