Separate the source of truth from the fast copy
Caching strategy names describe who fetches data and when writes reach durable storage. They do not automatically provide a consistency level. Define the authoritative record, the acknowledgement point, and the response to each partial failure.
Cache-aside: simple reads, nontrivial races
The application checks the cache, reads the database on a miss and fills the cache. For a write, it commits the database change and invalidates the cached value. The cache-aside pattern documentation explains this arrangement and its consistency limits.
Consider this hypothetical schedule:
A: cache miss; starts reading database version 7 B: commits version 8; deletes the cache key A: finishes its older read; stores version 7 in the cache C: reads version 7 from the newly filled cache
Deleting after a write is not enough to prevent a delayed reader from repopulating old data. A short TTL bounds one kind of staleness but does not make the read linearizable. Version-aware fills, an ordered invalidation stream or bypassing the cache after a write can help under explicitly defined assumptions. Any comparison of versions and cache update must be atomic where the race occurs.
Read-through: move fetch logic into a component
A read-through adapter performs the miss lookup for the application. It can centralize request coalescing, timeout rules and metrics. This is an ownership distinction from cache-aside, not a guarantee that values remain fresh. The adapter still needs an invalidation strategy and a decision about unavailable origins.
Write-through: acknowledge after the intended writes
A write-through path synchronously updates the backing store through a cache layer. Specify the ordering and what happens if one write succeeds and the other fails. Two separate systems do not become one atomic transaction because a diagram places them in sequence.
Consider a write-through adapter that commits a profile update to the database, then times out while installing the new cache value. The authoritative update may be successful while the cache is stale. Define whether the caller receives committed success or an error requiring an idempotent retry, and how every reader avoids that stale entry until recovery. A flag held only in one process does not protect other readers. An integrated transactional cache may provide different guarantees; verify its documented scope.
Write-behind: the cache now holds pending work
Write-behind acknowledges before the backing database update finishes. If acknowledged writes exist only in volatile memory, a cache failure can lose them. A durable queue and replayable consumer can protect pending work, but then this is a replication pipeline with its own ordering, deduplication and monitoring responsibilities.
Batching counters may be useful when the product tolerates delayed totals. It is inappropriate to silently apply the same loss model to confirmed purchases. An acknowledgement should tell the caller exactly which durability promise was satisfied.
Worked decision: product description versus inventory
Suppose a product page is read 500 times/s while descriptions change once an hour. We allow descriptions to be up to 30 seconds old. Cache-aside with expiry can be a reasonable starting point, provided repeated failures cannot keep extending stale data indefinitely.
The buy button has a different invariant: stock cannot go negative. It sends a conditional update to the authoritative store even if the displayed quantity came from a cache. If the purchase succeeds but the response is lost, retry with the same operation identifier. Cache selection does not solve duplicate effects.
| Pattern | Question to answer before use |
|---|---|
| Cache-aside | Can an old fill race with invalidation? |
| Read-through | Who limits concurrent miss requests? |
| Write-through | What happens after only one store updates? |
| Write-behind | Which durable record survives acknowledgement? |
Verify the contract
Test a crash between every two arrows in your write path. Replay invalidations out of order. Delay one old read until after a newer write, and compare the returned version. These experiments reveal more than labelling a pattern “high consistency.” Use caching overview and the capacity lab to account for normal misses and a cold cache.
Keep reading
Microservices Architecture
An architectural style that structures an application as a collection of loosely coupled, independently deployable services.
Cache Eviction Policies
When the cache is full, something has to go. A comprehensive guide to LRU, LFU, ARC, and other replacement algorithms with implementation details.
Circuit Breaker Pattern
A mechanism to prevent an application from repeatedly trying to execute an operation that's likely to fail.
Event Sourcing & CQRS
Comprehensive guide to Event Sourcing and Command Query Responsibility Segregation (CQRS) patterns, covering immutable event logs, state reconstruction, read/write separation, and real-world implementations in banking, e-commerce, and audit systems.
Scaling: Overview
A practical guide to scaling up and out, testing database and cache bottlenecks, and estimating failure headroom from measured workload rather than user counts.
API Gateway Pattern
The single entry point for microservices. Implementing rate limiting, authentication, and protocol translation/aggregation.