Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

Read-Through
HLD

Read-Through

Cache as a library — the cache itself fetches misses from the source, hiding the dance from application code.

The Pattern

 application talks ONLY to the cache; cache talks to the db:

 app:  value = store.get(key)          ← that's ALL app code

 [app] ──get──► [cache library/proxy]
                   │ hit → return
                   │ miss → loader(key):
                   │          fetch from db
                   │          store + return

              [ database ]

 the LOADER is registered once per entity type;
 every call site reuses it. miss-handling logic is WRITTEN ONCE.

vs Cache-Aside

 cache-aside:
   if missing: fetch, set, return      ← repeated at every call site
   drift risk: five services implement it five ways

 read-through:
   one loader definition; consistent behavior everywhere
   library enforces TTLs, negative caching, coalescing hooks

 same runtime behavior on hits; difference is WHERE THE LOGIC LIVES
 and how uniformly.

Where It Lives in Practice

 implementations of read-through semantics:

 - client libraries:   Caffeine (JVM), Cache2k with CacheLoader
 - process-local + distributed hybrid:
     Caffeine (L1) → Redis (L2) → DB, managed by a wrapping lib
 - proxy tiers:        caching proxies in front of storage
 - ORMs/frameworks:    Hibernate 2nd-level cache w/ providers

 Go's singleflight + explicit fill is effectively hand-rolled
 read-through — pattern matters more than product names.

What Good Loaders Include

 the registered loader is where hard problems get solved ONCE:

 - request coalescing    one flight per key (herd protection)
 - negative caching      cache "not found" briefly →
                         stop hammering db for deleted ids
 - jittered TTLs         avoid synchronized mass expiry
 - retry/backoff policy for source failures
 - metrics               hit rate per entity type out of the box
 
 these features are exactly what naive cache-aside code
 forgets at each call site — centralization IS the value.

Costs and Fit

✓ Wins✗ Costs
Uniform miss handlingLibrary/framework lock-in
Features implemented onceLoader must model ALL key types
Cleaner app codeLess visibility into what’s cached when
Easy L1+L2 stackingDebugging moves inside the library
 fit: high-traffic services where miss-handling correctness
 matters herd-wide. overkill: small apps, exotic per-call
 variation in freshness needs.

Interview Framing

Distinguish it crisply from cache-aside (“who fetches on miss?”) and land ONE concrete benefit — usually “negative caching and coalescing live in one place instead of being forgotten five times.” That sentence demonstrates production scar tissue, which is what the question is really probing.

My Private Notes

Notes are auto-saved locally to this device.