Cache Consistency Strategies and Best Practices for Database‑Cache Synchronization
This article explains why caching is essential for high‑read workloads, describes the consistency challenges when data resides in both MySQL and Redis, compares four cache‑update strategies, and offers practical recommendations such as using expiration, delayed double‑delete, message queues, and binlog subscription to achieve eventual consistency.
In real‑world business scenarios, data such as orders, members, and payments are persisted in databases for transactional guarantees, but relational databases often cannot handle very high QPS, leading to the need for caching.
Why Cache Matters
Cache replaces slower storage with faster space, improving read performance. Faster storage includes high‑performance media like Redis and local memory (L1/L2 caches), though local memory is limited and suitable only for hot keys.
Consistency Challenges After Introducing Cache
When data exists simultaneously in MySQL and Redis, any delay in synchronizing updates can cause inconsistency. The window of inconsistency is unavoidable without heavy mechanisms such as distributed transactions, which degrade performance.
Four Cache‑Update Strategies
The article examines four common approaches:
Update database then update cache
Update database then delete cache
Update cache then update database
Delete cache then update database
Each strategy is illustrated with timing diagrams and code examples.
1. Update Database → Update Cache
Typical code:
data = queryDataRedis(key);
if (data == null) {
data = queryDataMySQL(key); // cache miss, read from MySQL
if (data != null) {
updateRedis(key, data); // populate cache after DB read
}
}In write paths, updating the cache after the DB can cause stale data if concurrent writes reorder operations, as shown by a counter example where the cache ends up with value 99 while the DB holds 98.
2. Update Database → Delete Cache
Code example:
deleteRedis(key); // invalidate cache
updateMySQL(); // then write DBThis avoids writing stale data back to the cache but can still produce inconsistency under read‑write concurrency, e.g., a read thread may repopulate the cache with old data before the DB update completes.
3. Update Cache → Update Database
Code example:
updateRedis(key, data); // write cache first
updateMySQL(); // then write DBIf the DB update fails, the cache holds incorrect data, and rolling back the cache is unreliable.
4. Delete Cache → Update Database
Code example:
deleteRedis(key); // invalidate first
updateMySQL(); // then write DBThis strategy can still suffer from read‑write races where a read thread repopulates the cache with stale data before the DB write finishes.
Recommended Strategy
For read‑heavy, write‑light workloads, updating the database first and then deleting the cache is preferred because the inconsistency window is tiny (≈1 ms) and often negligible. For read‑write balanced scenarios, updating the database then updating the cache may be acceptable if the window can be ignored.
Ensuring Eventual Consistency
Set a reasonable expiration time on cache entries (e.g., 1 minute) so that any missed synchronization will be corrected when the entry expires and the next read falls back to the DB.
Use reliable message queues (at‑least‑once delivery) to send cache‑invalidating messages; if Redis is temporarily unavailable, retries ensure eventual key deletion.
Transactional MQ (e.g., RocketMQ) or a dedicated message table can guarantee that cache‑invalidating messages are sent together with DB updates.
Handling Complex Multi‑Cache Scenarios
When a single DB record maps to multiple cache keys (e.g., user profile, leaderboard, daily stats), each key must be updated or invalidated. To avoid scattered logic, publish a single MQ event after the DB change and let a dedicated service handle all related cache operations.
Alternatively, subscribe to MySQL binlog (using tools like Canal) to detect changes centrally and update caches accordingly.
Summary Table of Strategies
The article concludes with a comparative table summarizing concurrency patterns, potential problems, and mitigation techniques such as distributed locks, delayed double‑delete, or ignoring negligible windows.
Overall, the guidance helps architects design cache layers that balance performance and consistency for large‑scale internet services.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
IT Architects Alliance
Discussion and exchange on system, internet, large‑scale distributed, high‑availability, and high‑performance architectures, as well as big data, machine learning, AI, and architecture adjustments with internet technologies. Includes real‑world large‑scale architecture case studies. Open to architects who have ideas and enjoy sharing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
