Skip to content

Caching 101: Latency, Layers, and Eviction

Core Concept LearningJuly 16, 20265 min readUpdated July 21, 2026

A product page feels instant on the second visit because some layer reused work from the first. The useful beginner question is not “should we add Redis?” but “which copy answered, how old may it be, and what leaves when space runs out?”

This primer builds that model from the latency hierarchy through browser, edge, application, database, OS, and CPU caches, then explains hit/miss flow and eviction. Its canonical job is layers and eviction; use caching strategies for application patterns and Why Is Redis So Fast? for Redis mechanisms.

Caching: faster copy of hot data — less origin work
Caching: faster copy of hot data — less origin work

Why caching matters

A cache hit can avoid storage I/O, a network hop, a database query, or repeated computation. Which saving matters depends on the request: browser caching may remove the request entirely, a CDN may protect the origin, and a database buffer pool may make an app-level cache redundant. Measure before and after at the same percentile and workload.

Cache data that is reused and can tolerate a copy. Avoid shared caching for secrets and highly personal data unless keys, authorization, encryption, and expiry are designed together—a shared Redis key is not an access-control boundary.

Quick reference

  • Latency: compare measured hit and origin paths in the same environment.
  • Load: one origin read can populate a copy reused by later requests.
  • Scale: absorb spikes without linearly scaling Postgres.
  • Cost: fewer billed DB and egress calls.
  • Security: do not park PII or tokens in shared caches casually.

Remember this

A shared Redis key is not an access-control boundary — cache what's reusable and tolerant of a stale copy, and design keys, auth, and expiry together before any secret or PII ever touches a shared cache.

The latency hierarchy

Speed is a hierarchy, not a universal table. CPU caches are closest to execution, RAM avoids storage access, local storage avoids a remote hop, and a network service adds transport plus its own processing. Hardware, queueing, payload size, connection reuse, and cache warmth can move every observed number.

Use the hierarchy to form a hypothesis, then measure the actual path. If a product endpoint spends most of its time rendering or calling a second service, replacing a database read with Redis may barely change user latency. Pick the layer that removes the measured bottleneck, not the layer with the most impressive benchmark.

Latency ladder: CPU → RAM → SSD → HDD → network
Latency ladder: CPU → RAM → SSD → HDD → network

Quick reference

  • CPU cache: hardware-managed and closest to the processor.
  • Process memory: no service hop, but local to one process.
  • Redis/Memcached: memory-oriented, with client, network, queueing, and serialization costs.
  • Local storage and remote services: performance depends heavily on workload and environment.
  • Design to the budget: interactive UI ≠ batch analytics.

Remember this

Replacing a database read with Redis barely moves user latency when an endpoint actually spends its time rendering or calling a second service — pick the layer that removes the measured bottleneck, not the one with the best benchmark.

Seven types of caches

Caches stack from the browser inward. Browser holds static assets. CDN / edge (Cloudflare, Akamai) serves near the user. Application caches API or computed results. Database buffer/query caches live inside the engine. In-memory stores like Redis or Memcached sit beside the app. OS page cache speeds disk. CPU L1/L2/L3 is the innermost hardware layer.

Most product teams deliberately own browser headers, CDN rules, and Redis. OS and CPU caches still matter — they explain why warm boxes feel faster — but you configure them less often.

Request path Browser→CDN→App→In-memory→DB · OS/CPU are separate
Request path Browser→CDN→App→In-memory→DB · OS/CPU are separate

Quick reference

  • Browser — HTML/CSS/JS/images via Cache-Control.
  • CDN / edge — geography + origin shield.
  • Application — process or sidecar memoization.
  • Database — buffer pool / query result cache.
  • In-memory — Redis, Memcached for shared hot keys.
  • OS + CPU — automatic; measure, rarely micro-manage.
RedisMemcachedCloudflareAkamaiBrowser Cache-Control

Remember this

Browser, CDN, and Redis are the layers a team deliberately configures — OS and CPU caches explain why a warm box feels faster, but they run automatically and rarely need micro-management.

Hit vs miss: the request path

Trace one product request: browser and CDN miss, the application checks product:42, and Redis returns either a value or no value. On a miss, the app reads the database, handles a missing product as 404, attempts to populate Redis, and returns the database result. If Redis is unavailable, the database remains the fallback; if the database fails, the app returns a deliberate service error rather than caching an error page.

Use this path for reused catalog data. Be careful with inventory, money, permissions, and private responses: define freshness and authorization first, then choose a cache. A short TTL reduces the stale window but does not make a wrong cache key safe.

Zoom: after cache check, Hit and Miss are alternative branches
Zoom: after cache check, Hit and Miss are alternative branches

Quick reference

  • Hit = serve from cache; miss = load origin then populate.
  • Cold start and thundering herd are miss storms — use locks or jittered TTLs.
  • Fallback: if cache is down, still serve from origin.
  • Measure hit rate alongside origin load and end-to-end latency; a low ratio is only a problem when it misses the goal you set.
Origin-only lookup with explicit failures
1async function loadProduct(id: string): Promise<Product | null> {2  try {3    return await db.products.findById(id);4  } catch (error) {5    logger.error({ error, id }, "database read failed");6    throw new ServiceUnavailableError("Product service unavailable");7  }8}
Cache lookup with miss and outage fallback
1async function loadProduct(id: string): Promise<Product | null> {2  const key = `product:${id}`;3 4  try {5    const cached = await redis.get(key);6    if (cached !== null) return JSON.parse(cached) as Product;7  } catch (error) {8    logger.warn({ error, key }, "cache unavailable; using origin");9  }10 11  const product = await db.products.findById(id);12  if (product === null) return null;13 14  redis.set(key, JSON.stringify(product), "EX", 300).catch((error) => {15    logger.warn({ error, key }, "cache fill failed");16  });17  return product;18}

Remember this

A short TTL shrinks the stale window but doesn't make a wrong cache key safe — if Redis is down the database is still the fallback, but a database failure needs a deliberate service error, never a cached error page.

Eviction: what leaves when memory is full

Caches are finite. LRU drops what has not been touched longest. LFU drops lowest access counts. FIFO drops oldest inserts. TTL expires entries by clock regardless of popularity. Random is simple and sometimes good enough under uniform access.

Many systems combine TTL with LRU: expire stale data and, under pressure, evict cold keys. Wrong policy looks like thrashing — hot keys bouncing in and out — or stale pages living forever.

Eviction policies when the cache is full
Eviction policies when the cache is full

Quick reference

  • LRU — default mental model for web hot keys.
  • LFU — good when frequency beats recency.
  • FIFO — predictable; ignores popularity.
  • TTL — freshness contract; pair with invalidation on writes.
  • Random — cheap; works when access is fairly uniform.

Remember this

The wrong eviction policy shows up as hot keys thrashing in and out or stale pages that never leave — TTL paired with LRU is what expires stale data while still evicting cold keys under memory pressure.

Best practices and where teams use caches

Start from the request path: browser → edge → application → shared cache → database. At each step ask whether the response is reusable, who may see it, how stale it may become, and whether the next layer can absorb misses. Stop adding layers when the measured bottleneck moves elsewhere.

Common candidates include versioned static assets, public API responses, media, search results, catalogs, carefully scoped sessions, inference outputs, and templates. Prices, permissions, and personalized pages need stronger invalidation and key isolation than a public image.

Right data · right place · right time
Right data · right place · right time

Quick reference

  • Prefer cache-aside + TTL for most CRUD reads.
  • Invalidate on write for catalogs that must feel instant.
  • CDN for public static; Redis for shared dynamic hot keys.
  • Sessions: short TTL + secure cookies; avoid dumping full PII blobs.
  • Decision flow: locate repeated work → choose the nearest safe layer → define key and freshness → force hit, miss, expiry, and outage → compare origin load.

Remember this

Prices, permissions, and personalized pages need stronger invalidation and key isolation than a public image — stop adding cache layers once the measured bottleneck has actually moved elsewhere.

Key takeaway

Caching is a stack of copies plus policies for freshness and memory pressure. Place a cache only where it removes repeated work, and keep the source-of-truth and failure path visible.

Practice (20 min): Choose one endpoint and instrument exactly one cache layer; the first request should miss and read the source, while the second should hit and return the same value. Intentionally expire the key, request a missing record, and stop the cache. Recover by repopulating after expiry and using the documented source or error path during outage. Pass when logs distinguish hit, miss, expiry, negative lookup, and outage, and your chosen eviction policy has one workload-based justification. Then use Caching Strategies to choose the application pattern.

Share:

Related Articles

A product page is easy to cache until a price changes: the CDN still has the old response, one app instance has an older

Read

In-memory caching is an essential component of high-throughput web architectures, reducing database read load and accele

Read

A Redis GET can be constant-time and still miss its latency target when a large Lua script is ahead of it, the client op

Read

Keep learning

Follow a structured path or browse all courses to go deeper.