Understanding Redis and MySQL Data Consistency and Caching Strategies
This article explains when and how to use caching with Redis, compares recursive and table‑lookup algorithms for factorial calculation, discusses cache design, expiration policies, and presents several write‑through and write‑behind strategies to maintain data consistency between Redis and MySQL under various concurrency scenarios.
Preface
Hello everyone, I am Wukong. This article provides a thorough explanation of Redis and MySQL data consistency issues.
As web traffic and concurrency increase, projects often need architectural upgrades. The following situations may arise:
If page concurrency is low, MySQL alone can support the business logic, so caching is optional; static pages may be cached.
When concurrency rises and the database becomes a bottleneck, especially for data that is read frequently or queried slowly, caching high‑hit objects in Redis can avoid costly DB reads.
Other techniques such as static page caching, CDN acceleration, or load balancing can also improve concurrency, but are not covered here.
Cache Thinking Is Everywhere
We start with an algorithm problem to illustrate the value of caching.
Problem 1:
Given an integer n (n<20), compute n!.
Analysis 1:
Ignoring overflow, we know n! = n * (n‑1) * … * 1 = n * (n‑1)!. A recursive function can solve it.
static long jiecheng(int n) {
if (n == 1 || n == 0) return 1;
else {
return n * jiecheng(n - 1);
}
}This requires n recursive calls for each computation.
Problem 2:
Given t test cases, each with a number xi (xi<20), compute xi! for every case.
Analysis 2:
Using recursion for each case leads to O(n²) time when t or xi is large.
Instead, we can use a lookup table (pre‑computed factorials). Allocate an array, fill it once, and retrieve values in O(1) time.
import java.util.Scanner;
public class test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
long[] jiecheng = new long[21];
jiecheng[0] = 1;
for (int i = 1; i < 21; i++) {
jiecheng[i] = jiecheng[i - 1] * i;
}
for (int i = 0; i < t; i++) {
int x = sc.nextInt();
System.out.println(jiecheng[x]);
}
}
}The time complexity becomes O(n), and the idea mirrors cache usage: compute once, store, and reuse.
Cache Application Scenarios
Caching is suitable for high‑concurrency environments to increase service capacity. It moves frequently accessed or expensive‑to‑compute data from slow storage (e.g., disk‑based relational databases) to fast memory‑based storage such as Redis.
Relational databases suffer from:
Slow read/write I/O.
Heavy computation to derive data.
By caching, we reduce disk I/O and computation, achieving faster reads via memory and hash‑based lookups.
For moderately sized websites, caching is often necessary, and Redis is a popular choice.
Things to Watch Out For
Improper cache usage can cause many problems, especially data consistency issues, which are discussed in detail later.
Whether to Use Cache
Do not use cache just for the sake of it. If the application demands extremely high data consistency, experiences frequent writes with few reads, or has negligible concurrency, caching may add unnecessary complexity and risk of inconsistency.
Reasonable Cache Design
When caching multi‑table queries, decide whether to split keys or combine them based on business needs; there is no universal rule.
Expiration Strategy Selection
Cache stores hot data, but Redis resources are limited. Choose an eviction policy (FIFO, LRU, OPT, LFR) similar to OS cache algorithms. FIFO based on time is easy to implement, and Redis supports per‑key expiration.
Set expiration times according to system performance; too short reduces hit rate, too long keeps stale data.
Data Consistency Issues ★
When consistency requirements are strict, caching may be unsuitable. Below are common consistency scenarios for Redis caches.
Read
Read from Redis; if the key is missing, fetch from MySQL and update the cache.
Write 1: Update DB then Cache (low concurrency)
First update MySQL, then update Redis. If the cache update fails, DB and cache diverge (DB newer, cache stale).
Write 2: Delete Cache then Update DB (low concurrency optimization)
Delete the cache, update MySQL, and let the next read repopulate the cache. This avoids the failure case of Write 1 but only works well under low concurrency.
Write 3: Delayed Double‑Delete Strategy
Delete the cache, update MySQL, then delete the cache again after a short delay (hundreds of ms) to handle race conditions where a read occurs between DB update and cache repopulation.
Write 4: Write Directly to Cache, Periodically Sync to DB (high concurrency)
For heavy write traffic, operate on Redis and periodically flush changes to MySQL. This makes Redis the primary data store and MySQL a backup, often combined with message queues or locks to ensure ordering and reliability.
In summary, the higher the concurrency and the stricter the consistency requirement, the more complex the cache consistency design becomes. The above strategies illustrate common trade‑offs and potential pitfalls when integrating Redis with MySQL.
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.
Wukong Talks Architecture
Explaining distributed systems and architecture through stories. Author of the "JVM Performance Tuning in Practice" column, open-source author of "Spring Cloud in Practice PassJava", and independently developed a PMP practice quiz mini-program.
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.
