Caching

Reduce repeated work and absorb uneven read traffic with caches.

In this article
Fig 1A hit avoids downstream work
STUDY MODEL
Inspect one part at a timeDispatch
  1. Dispatch

    The client sends a request to the dispatcher.

  2. Cache hit

    Return the cached value without executing the illustrated worker/database path.

  3. Cache miss

    A worker from the pool reads durable storage and produces the result.

  4. Pool

    Worker 1, Worker 2, and Worker n illustrate independent work capacity. Cache freshness still needs a policy.

The dispatcher can return a cached hit; a miss needs downstream work.

How to read this model

A fast retrieval drawer beside a worker magazine and durable archive. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.

Original redraw based on Scalable system design patterns.

A cache stores a prior result so the next request can avoid the original work. It reduces page load time and load on application servers and databases. Popular records can create a hot spot in a database even when average traffic is balanced. A cache can absorb that uneven load.

Cache locations

  • A client cache in the browser or operating system avoids a network request.
  • A CDN caches content at edge locations.
  • A reverse proxy can return cached static or dynamic responses.
  • A database usually caches pages and indexes internally. Tune those settings for measured workloads.
  • An application cache such as Redis or Memcached sits between the application and durable storage.

RAM is faster but smaller than disk. An eviction policy such as least recently used (LRU) removes cold entries to keep hot data in memory. Avoid file-based caches when nodes need to be cloned or autoscaled.

Cache rows, query results, assembled objects, or fully rendered HTML. Query caching can save work but makes invalidation hard when one changed row affects many query results. Object caching gives the application a smaller set of keys to invalidate. Useful objects include user sessions, rendered pages, activity feeds, and user-graph data.

Redis also provides persistence and data structures such as sorted sets and lists. Those features do not make it a replacement for a durable database without an explicit recovery design.

Cache-aside

The application owns both the cache lookup and the database read:

  1. Look up the key in the cache.
  2. On a miss, load the value from the database.
  3. Store the value in the cache.
  4. Return the value.
def get_user(user_id):
    key = "user.{0}".format(user_id)
    user = cache.get(key)
    if user is None:
        user = db.query(
            "SELECT * FROM users WHERE user_id = {0}".format(user_id)
        )
        if user is not None:
            cache.set(key, json.dumps(user))
    return user
Fig 2Load on a miss, then populate the cache
STUDY MODEL
Inspect one part at a timeLookup
  1. Lookup

    The application checks the cache.

  2. Miss

    On a miss, the application loads the value from the database.

  3. Populate

    The application stores the loaded value in cache.

  4. Return

    Return the result. Cache and database can diverge without an appropriate invalidation strategy.

In cache-aside, the application owns the cache lookup and population.

How to read this model

A lookup drawer with a transfer carriage to the durable archive. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.

Original redraw based on From cache to in-memory data grid.

Memcached is often used this way. Lazy loading caches only requested data, so unused records do not fill the cache.

Each miss adds cache and database trips. A database update can leave a stale entry until its TTL expires or the write path invalidates it. A new cache node starts empty and causes a burst of misses.

Write-through

The application writes to the cache. The cache synchronously writes the durable store, then returns:

set_user(12345, {"foo": "bar"})
def set_user(user_id, values):
    user = db.query("UPDATE Users WHERE id = {0}".format(user_id), values)
    cache.set(user_id, user)
Fig 3Acknowledge only after the durable write
STUDY MODEL
Inspect one part at a timeWrite cache path
  1. Write cache path

    The application sends the write through the cache.

  2. Database

    The cache synchronously writes the database.

  3. Acknowledge

    Acknowledge the application after database success. Handle failure so the cache does not falsely advertise success.

The write-through acknowledgement follows database success.

How to read this model

A coupled write fixture with a downstream commit latch. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.

Original redraw based on Scalability, availability, stability, patterns.

Writes take the database latency, but a successful write is immediately available in the cache. A new cache node remains empty until values are written or warmed. Pairing write-through with cache-aside handles reads that populate missing entries. A TTL limits storage for values that are written but never read.

Write-behind

Write-behind, or write-back, acknowledges a cache update and writes the durable store asynchronously. It improves write latency and can combine multiple updates. A cache failure before the write reaches storage can lose data. The implementation needs a durable queue, ordering rules, retries, and recovery behavior.

Fig 4A fast response leaves durable work pending
STUDY MODEL
Inspect one part at a timeWrite
  1. Write

    The application writes through the cache path.

  2. Enqueue

    Record pending persistence work in a durable queue according to the design.

  3. Acknowledge

    The application can receive success before the database update finishes.

  4. Persist later

    An event worker writes the database. Recovery, ordering, and failure policy remain necessary.

Write-behind separates acknowledgement from the later database write.

How to read this model

A write tray feeding a durable queue and later storage press. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.

Original redraw based on Scalability, availability, stability, patterns.

Refresh-ahead

Refresh-ahead reloads a recently used entry before its TTL expires. It can avoid a miss for predictable hot keys. If the prediction is wrong, refresh work consumes resources for entries no one requests.

Fig 5Refresh before the cached value expires
STUDY MODEL
Inspect one part at a timeRead
  1. Read

    The client reads the cached value.

  2. Near expiry

    The refresh policy identifies an entry approaching its TTL.

  3. Reload

    A refresh worker loads the current value from storage.

  4. Replace

    Replace the cache entry before expiry when refresh succeeds.

Refresh-ahead aims to reload before expiry; refresh failure still needs a freshness policy.

How to read this model

A cache drawer beside an expiry dial and refresh carriage. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.

Original redraw based on From cache to in-memory data grid.

Invalidation is part of the design

Decide what happens on a database write, cache failure, TTL expiry, and partial update. A stale value can be acceptable for a feed but not for an authorization decision. A cache is not free consistency. It adds keys, expiry, eviction, warm-up, and failure behavior to the system.

See consistency patterns for the guarantees readers need and databases for the source of truth.

Further reading

Keep track of your reading.

Your reading progress stays in this browser.