Caching

Caching Fundamentals

A cache trades memory for latency by keeping a fast, small copy of data in front of something slow and large — and it only helps if the hit ratio is high enough to matter.
  • A cache is only valuable when access has locality (temporal: same key soon again; spatial: nearby keys together) — caching purely random access helps nothing
  • Cache-aside (lazy loading): the application checks the cache first, and on a miss reads the source of truth and populates the cache itself — the most common pattern
  • Read-through: the cache is responsible for loading on a miss, transparent to the application — simpler call sites, less flexible
  • Eviction policy decides what gets thrown out when the cache is full: LRU (evict least-recently-used), LFU (evict least-frequently-used), or TTL (evict by age) — the right one depends on the access pattern
  • Caches exist at every layer of a system simultaneously: browser, CDN, reverse proxy, application (Redis/Memcached), and the database's own buffer pool
Cache-aside read path
The application owns the miss-fill logic; the cache itself stays a simple key-value store
Eviction policies
PolicyEvictsGood fit
LRULeast recently accessed itemGeneral-purpose — recency predicts reuse
LFULeast frequently accessed itemStable popularity distributions (some keys always hot)
TTLItems older than a fixed ageData with a natural freshness window (quotes, weather)
Cache-aside get() in Java
Optional<Profile> getProfile(String userId) {
    Profile cached = cache.get(userId);
    if (cached != null) return Optional.of(cached);

    Optional<Profile> loaded = database.findProfile(userId);
    loaded.ifPresent(p -> cache.put(userId, p, Duration.ofMinutes(10)));
    return loaded;
}
Sources
  • Designing Data-Intensive ApplicationsCh. 3 — Storage and Retrieval (caching layers)
  • System Design Interview – An Insider's GuideCh. 1 — Cache