Cache Consistency Strategies: How to Safely Update Cache and Database

A practical discussion on cache update strategies using Redis, focusing on consistency, concurrency, and real interview scenarios.

Cache Consistency Strategies: How to Safely Update Cache and Database

A practical discussion on cache update strategies using Redis, focusing on consistency, concurrency, and real interview scenarios.

Victory

Introduction

In modern web systems of a certain scale, caching is almost always introduced to reduce database pressure and improve response times.

Redis is a very common choice for this purpose.

During recent interviews, cache-related questions came up frequently. One particularly interesting topic was:

How should cache be updated to ensure data consistency under high concurrency?

This article walks through a real interview discussion and arrives at a practical solution.

Typical Cache Architecture

In most systems, the cache architecture looks like this:

Client -> Cache (Redis) -> Database

The typical read flow is:

  1. Read data from cache
  2. If cache hit, return data directly
  3. If cache miss, read from database and write back to cache

This works well for read-heavy, write-light scenarios.

Interview Scenario

During an interview, I mentioned that I had used Redis to cache frequently read but rarely updated data, such as:

  • Game configuration
  • Activity configuration
  • User history data

The interviewer then asked:

What cache update strategy do you use?

My initial answer was:

Update the database first, then update the cache.

The interviewer followed up:

What if the database update succeeds, but the cache update fails?

This would lead to data inconsistency.

Naïve Solutions and Their Problems

Delete Cache Before Updating DB

I suggested:

Delete the cache first, then update the database.

The interviewer pointed out another race condition:

  1. Cache is deleted
  2. Database update has not completed yet
  3. Another request reads old data from DB and writes it back to cache

Result: stale data re-enters the cache.

Locking

Another idea was:

Lock the data during update.

While locking can work, it significantly reduces concurrency and scalability.

Clearly, a better approach is needed.

Problem Restatement

Assume a table:

account(uid, balance)

Characteristics:

  • Read-heavy
  • Write-light

The read flow:

  1. Read from cache
  2. On miss, read from DB and populate cache

The key questions:

  1. Update cache or delete cache?
  2. Update DB first or cache first?

1. Prefer Cache Eviction Over Update

Updating cache can be complex and error-prone.

Cache eviction is simpler and usually results in only one extra cache miss.

Therefore:

Prefer deleting cache entries instead of updating them.

2. Operation Order Matters

Compare the two strategies:

DB First, Then Evict Cache

  • DB update succeeds
  • Cache eviction fails
  • Cache contains stale data → inconsistency

Evict Cache First, Then Update DB

  • Cache eviction succeeds
  • DB update fails
  • Only causes one cache miss

Evict cache first, then update DB

3. Serialize Access to the Same Data

To further reduce race conditions, ensure serialized access for the same data item.

Possible approaches:

  • Route requests by hashing id to the same service instance
  • Route DB connections by hashing id
  • Ensure single-writer semantics per key

Final Takeaways

  • Cache consistency is a classic distributed systems problem
  • Cache eviction is safer than cache update
  • Always evict cache before updating the database
  • Serializing access can further reduce inconsistencies

References

  • Cache Architecture Design Details
  • Cache and Database Consistency
  • Redundancy Data Consistency Patterns