Redis & Valkey Explained Visually: Cache-Aside, Write-Through, and Preventing Cache Stampedes
The Redis Licensing Schism and the Rise of Valkey
In-memory data stores form the backbone of modern web performance. For over fifteen years, Redis served as the undisputed standard for sub-millisecond caching, session state management, and pub/sub message brokers. However, the commercial licensing shifts of recent years prompted the open-source community—backed by the Linux Foundation, AWS, Google Cloud, and enterprise Linux distributions—to fork the codebase into Valkey.
Valkey preserves the open BSD-3-Clause license, maintains 100% wire-protocol compatibility with Redis 7.2 clients, and introduces performance optimizations in multi-threaded socket handling on Debian. Whether your cluster runs Redis or Valkey, treating the in-memory engine as a simplistic key-value bucket without architectural discipline leads directly to memory fragmentation, stale data corruption, and catastrophic database outages.
IN-MEMORY STORE EVOLUTION: REDIS TO VALKEY
- ORIGINAL OPEN-SOURCE REDIS (BSD-3-Clause)
- Commercial Redis (Dual Proprietary License SSPLv1/RSALv2)
- VALKEY (Linux Foundation Open Source Governance)
- 100% Drop-in Binary & Protocol Replacement
- Multi-threaded Event Loop Enhancements
- Native Support in Enterprise Linux Package Trees
At Webxtek, we engineer systems where in-memory caching acts as a predictable shock absorber. Pairing low-latency memory stores with our high-performance website platforms and scalable web application architectures ensures that high-volume platforms absorb viral traffic spikes with zero degradation.
Architectural Caching Patterns: Cache-Aside vs. Write-Through
The two dominant caching patterns reflect fundamentally different operational trade-offs regarding data freshness and latency.
1. The Cache-Aside (Lazy-Loading) Pattern
In Cache-Aside, the cache engine has no direct relationship with the database. The application layer orchestrates all interactions:
CACHE-ASIDE (LAZY-LOADING) REQUEST FLOW
- Client Requests User Profile (ID: 481)
-
- App Queries Valkey/Redis → Cache Hit? → Return Profile (0.4ms)
- (Cache Miss!)
-
- App Queries PostgreSQL Database (12ms)
- App Writes Result to Valkey with TTL (e.g., SET user: 481 … EX 3600)
-
- Return Profile to Client
Advantages: Resilient to cache failure (a down cache simply degrades to database queries); memory is only consumed by requested items.
Disadvantages: Initial cache miss penalty; risk of serving stale data if database updates bypass cache invalidation.
2. The Write-Through Pattern
In Write-Through, the cache sits inline between the application and the persistent store. When data is modified, the application writes to the cache, which writes synchronously to PostgreSQL before confirming success.
WRITE-THROUGH SYNCHRONOUS MUTATION
- Application Mutation Request
- In-Memory Store: Valkey: (Atomic Write) → [ Persistent PostgreSQL DB ]
- Both Confirmed Success
- Return HTTP 200 OK to Client
The Thundering Herd: Cache Stampede Prevention
A cache stampede occurs when a heavily requested key expires. Consider a homepage catalog payload queried by 800 concurrent requests per second. The moment its TTL expires at 12:00:00, all 800 threads experience a cache miss simultaneously. Each thread attempts to compute the expensive database query, spiking CPU usage to 100% and crashing the database engine.
THE CATASTROPHIC CACHE STAMPEDE (THUNDERING HERD)
- Hot Key
catalog:featuredExpires at 12:00:00! - Request 1 (Miss)
- Request 2 (Miss) → [ 800 Concurrent Database Queries! ]
- Request 3 (Miss) → [ PostgreSQL Connection Pool Exhausted ]
- Request 800 (Miss) → [ Web Server Drops HTTP 504 Timeouts ]
The Solution: Distributed Mutex Locking (SETNX)
To prevent stampedes, only the first thread that encounters a miss is permitted to query the database. All subsequent threads either wait or receive a slightly stale cached payload:
// Node.js implementation of distributed mutex lock with fallback
async function getCachedCatalog(redisClient, dbClient) {
const cacheKey = "catalog:featured";
let data = await redisClient.get(cacheKey);
if (!data) {
const lockKey = `lock:${cacheKey}`;
// Acquire distributed lock for 5 seconds using atomic NX
const acquired = await redisClient.set(lockKey, "locked", "NX", "EX", 5);
if (acquired) {
try {
// Only one worker queries the database
data = await dbClient.query("SELECT * FROM products WHERE featured = true");
await redisClient.set(cacheKey, JSON.stringify(data), "EX", 300);
} finally {
await redisClient.del(lockKey);
}
} else {
// Other workers sleep 50ms and retry or return stale fallback
await new Promise((r) => setTimeout(r, 50));
return getCachedCatalog(redisClient, dbClient);
}
}
return JSON.parse(data);
}
Memory Eviction Policies: volatile-lru vs. allkeys-lru
When Valkey reaches its allocated memory limit (maxmemory), it must evict existing keys to accommodate new writes. Selecting the wrong policy will cause unpredictable data loss.
Configure /etc/valkey/valkey.conf:
# Cap memory allocation to 4 Gigabytes
maxmemory 4gb
# Choose eviction strategy carefully
maxmemory-policy volatile-lru
# Number of keys sampled for LRU approximation
maxmemory-samples 7
VALKEY MEMORY EVICTION POLICIES
- POLICY: volatile-lru
- Only evicts keys that have an explicit EXPIRE / TTL set.
- SAFEST for mixed instances containing sessions, queues, and caches.
- If no TTL keys remain, writes throw OOM errors rather than dropping data.
- POLICY: allkeys-lru
- Evicts ANY key based on least-recently-used heuristics.
- IDEAL for pure caching instances where every key can be recomputed.
- DANGEROUS if persistent background jobs or queues reside in the instance.
Production Deployment and Persistence Choices
Configuring Valkey for production requires choosing between Redis Database snapshots (RDB) and Append-Only Files (AOF). For pure caching tiers, disabling persistence entirely (save "" and appendonly no) yields the lowest latency and eliminates disk I/O bottlenecks.
For stateful sessions, configure hybrid persistence:
# Enable AOF with fsync every second
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
You can review production tuning scripts hosted on GitHub to integrate Valkey metrics into Prometheus.
Combining memory-tuned Valkey instances with our scalable managed hosting solutions ensures that your web applications deliver lightning-fast responses without sacrificing transactional data integrity.
In practice, we apply these exact architectural standards across specialized sectors including b2b saas platforms and cloud computing & iaas providers. Whether you are modernizing core workflows through high-performance websites and managed hosting for websites and apps, connecting sector-specific requirements to disciplined execution is what turns technical theory into compounding commercial advantage.
[+] [ INDEX_DIRECTORY ] 16 topics ▼
- The Redis Licensing Schism and the Rise of Valkey
- Architectural Caching Patterns: Cache-Aside vs. Write-Through
- 1. The Cache-Aside (Lazy-Loading) Pattern
- 2. The Write-Through Pattern
- The Thundering Herd: Cache Stampede Prevention
- The Solution: Distributed Mutex Locking (SETNX)
- Memory Eviction Policies: volatile-lru vs. allkeys-lru
- Production Deployment and Persistence Choices
- Author
- Frequently Asked Questions
- What is the architectural difference between Redis and its open-source fork Valkey?
- What causes a cache stampede (thundering herd) and how do you prevent it?
- Why is volatile-lru often preferred over allkeys-lru in mixed Redis deployments?
- What is the difference between Cache-Aside and Write-Through caching patterns?
- Related Nodes
- Path Sequence
Frequently Asked Questions
What is the architectural difference between Redis and its open-source fork Valkey?
Following Redis's license transition to non-open-source terms, the Linux Foundation created Valkey. Valkey continues pure BSD-licensed development with multi-threaded I/O optimizations and identical command protocol compatibility.
What causes a cache stampede (thundering herd) and how do you prevent it?
A stampede occurs when a high-traffic cached key expires, causing hundreds of concurrent client threads to simultaneously execute the expensive backend database query. It is prevented using distributed mutex locks or probabilistic early expiration (XFetch).
Why is volatile-lru often preferred over allkeys-lru in mixed Redis deployments?
volatile-lru only evicts keys configured with an explicit Time-To-Live (TTL), ensuring that permanent persistent data or message queues stored in the instance are never dropped when memory fills.
What is the difference between Cache-Aside and Write-Through caching patterns?
In Cache-Aside, the application reads from cache and lazily populates it from the database on a miss. In Write-Through, the application writes directly to the cache, which synchronously updates the database before completing.
[ RELATED_NODES ]
> START_PROJECT
Need a website that earns trust, ranks in search, and gives your business a stronger digital presence? Start the conversation here.