Cache Consistency: Challenges and Strategies for Backend Systems
This article examines why cache consistency cannot be fully guaranteed, analyzes common inconsistency scenarios between Redis and MySQL, compares four update strategies, and offers practical recommendations such as updating the database before deleting cache, using short expiration times, delayed double‑delete, MQ or binlog approaches to achieve eventual consistency.
In real business scenarios, data such as orders, members, and payments are persisted in databases like MySQL, which provide strong transactional guarantees but may struggle with high QPS under large traffic. Because most traffic consists of read requests on relatively static data, caching becomes essential to improve read performance.
Cache significance : Caching replaces slower storage with faster memory (e.g., Redis) or local in‑process memory, effectively trading space for time.
Consistency challenges : When data exists simultaneously in Redis and MySQL, any delay in synchronizing updates creates a window of inconsistency. This window cannot be eliminated entirely because database and cache updates are not atomic; failures or network delays can leave stale data in the cache.
Four cache‑update strategies
1. Update DB then update cache – may cause a brief period where reads see old cache data.
2. Update cache then update DB – risky because if the DB update fails, the cache holds incorrect data.
3. Update cache then update DB (no concurrency) – requires reliable messaging or distributed locks.
4. Delete cache then update DB – avoids stale cache but can lead to read‑write race conditions; often mitigated with a delayed double‑delete.
Overall, updating the database first and then deleting the cache provides the best trade‑off for read‑heavy workloads.
Practical recommendations
• Set a short expiration time (e.g., 1 minute) on cache entries to bound the inconsistency window.
• Use a delayed double‑delete strategy: after the DB update, delete the cache, wait a short period, then delete again to handle race conditions.
• Employ reliable message queues (MQ) with at‑least‑once delivery to ensure cache invalidation even if a service crashes. Example:
deleteRedisKey(key); // send MQ message to invalidate cache• For complex scenarios where a single DB change affects multiple cache keys, publish an MQ message or use MySQL binlog listeners (e.g., Canal) to centralize cache updates.
• When using MQ, consider transactional messages (e.g., RocketMQ) or a message table to guarantee that DB updates and cache‑invalidations are atomic.
By combining these techniques—proper expiration, careful ordering of DB and cache operations, delayed double‑delete, and reliable messaging—systems can achieve eventual consistency between Redis and MySQL while maintaining high performance.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.