The checkout cache is behaving normally until a traffic spike pushes Redis toward its memory limit. Then cached entries disappear, hit rate falls, and requests start leaning on the database or an upstream validation service. The first instinct is often to add memory or shorten TTLs, but neither fix answers the key question: which keys is Redis allowed to remove, and what happens when it can't?
Redis cache eviction isn't just a performance setting. The policy draws a boundary around what data may be discarded under pressure. Choose poorly, and Redis can evict state the application needs, refuse writes, or leave persistent keys blocking new cache entries. A reliable setup starts by classifying the data in the instance, then matching its eviction policy to what can safely be lost.
Table of Contents
- Why Eviction Policy Matters in Production
- How Redis Decides What to Evict
- The Eight Eviction Policies and When Each One Fits
- LRU vs LFU vs TTL vs Random Signals Explained
- Eviction Is Not Expiration and TTL Is Not Protection
- Tuning maxmemory and Monitoring the Right Metrics
- Production Walkthrough Tuning a Validation Cache
- Operational Playbook for Stable Redis Caching
Why Eviction Policy Matters in Production
A checkout cache can look healthy for months, then become unpredictable during a busy period. The database or external API sees more requests as cache hits decline. Engineers see memory climbing and may assume Redis is cycling out old entries. But the configured policy might only be allowed to evict keys with expiration timestamps, while some keys in the same instance have no TTL at all.
That distinction turns a routine capacity issue into an application risk. Cached validation responses are disposable, but a Redis instance might also contain sessions, locks, rate-limit counters, or workflow state. If the policy treats all of those keys as equally eligible, a memory event can erase data that wasn't meant to be a cache. If it treats too few keys as eligible, writes can fail even while Redis contains data the application could safely recompute.
Practical rule: Decide what Redis may lose before choosing how it should pick a key.
A useful way to think about Redis cache eviction is as a data-safety boundary with performance consequences. The policy affects which values survive memory pressure, how often the application experiences misses, and whether writes continue when space runs short. That makes it an operational choice, not a one-time tuning detail to set and forget.
Start by inventorying the keys in the instance and identifying which ones are disposable. If the instance contains only recomputable cache entries, broad eligibility may be appropriate. If it contains durable or operational state, separate those key classes or isolate them in different Redis instances rather than hoping a policy can infer business importance from access patterns.
How Redis Decides What to Evict
Redis uses the configured maxmemory limit and maxmemory-policy to decide when and how to remove keys. Eviction becomes relevant when a write needs additional memory beyond the configured limit. The policy then answers two different questions: which keys can be considered, and what signal selects a victim. Redis documents the memory-limit and policy model.

Think of a shared office drawer. The first decision is whether Redis can remove any folder in the drawer or only folders carrying a removable label. The second is how it chooses a folder: one nobody opened recently, one nobody opens often, one with the shortest remaining lifetime, or a random one. Redis uses the same two-part logic, though the selection signal is encoded in the policy name.
Two choices are hiding in the policy name
The eligible keyspace is either the whole keyspace or only keys with an expiration timestamp. The selection signal is based on recency, frequency, remaining TTL, or randomness. The policy combines those dimensions: allkeys-lru, for example, means every key is eligible and the least recently used key is the target.
This model is more useful than memorizing policy names. Ask first whether Redis may remove every key in the instance. Then decide what makes one eligible key a better eviction candidate than another. That order keeps data safety ahead of algorithm preference.
Redis doesn't evict a key just because it has a TTL. An expiration timestamp can make a key eligible for a volatile-* policy, but memory pressure and elapsed TTL are separate causes of removal. Those two mechanisms should be designed and monitored separately.
The Eight Eviction Policies and When Each One Fits
The first decision is all keys versus keys with an expiration timestamp. allkeys-* policies can consider every key in the database. volatile-* policies can consider only keys that have a TTL, which means persistent keys are outside their reach.
Policies that consider every key
allkeys-lruremoves the least recently used key. It suits a dedicated cache where every stored value can be recomputed.allkeys-lfuremoves the least frequently used key. It suits a cache where keeping repeatedly accessed hot entries matters more than preserving recently accessed, one-off entries.allkeys-randomchooses a key randomly. It can fit when the application has no useful access signal and simple selection is preferable.
Policies limited to expiring keys
volatile-lruchooses the least recently used key among keys with a TTL.volatile-lfuchooses the least frequently used expiring key.volatile-randomchooses randomly among expiring keys.volatile-ttlprioritizes expiring keys with the shortest remaining TTL.
These policies can work when TTLs intentionally define which data may be removed. They create a trap in mixed workloads, though: if expiring keys run out, persistent keys remain ineligible. Redis may then be unable to make room for writes.
When preserving existing keys takes priority
noeviction doesn't remove existing data to satisfy a write. When Redis reaches its memory limit, a write that needs more space returns an error instead. That may be appropriate when automatic deletion is unacceptable and the application is built to handle rejected writes, but it isn't a hands-off cache policy.
| Policy | Eligible keys | Selection signal | Best for |
|---|---|---|---|
allkeys-lru |
All keys | Least recently used | Dedicated, disposable cache |
allkeys-lfu |
All keys | Least frequently used | Cache with durable hot spots |
allkeys-random |
All keys | Random | Workloads without a useful signal |
volatile-lru |
Keys with TTL | Least recently used | Expiring cache entries |
volatile-lfu |
Keys with TTL | Least frequently used | Expiring entries with hot spots |
volatile-random |
Keys with TTL | Random | Expiring entries without a useful signal |
volatile-ttl |
Keys with TTL | Shortest remaining TTL | Data whose retention window should guide removal |
noeviction |
None | No key selected | Writes must fail rather than evict |
For a cache-only instance, allkeys-lru is often a practical starting point, provided every value is safe to lose. For a mixed-purpose instance, separate cache data from state that must survive, rather than assuming a volatile-* policy will protect the right keys.
LRU vs LFU vs TTL vs Random Signals Explained
An API response cache sees a burst of requests for previously quiet endpoints. A session store on the same workload holds state users still need. The access pattern may look similar, but the cost of losing an entry is different. Choose a signal only after deciding whether those losses are acceptable.

Match the signal to the workload
LRU, or least recently used, is a practical fit for request-driven API caches when recent traffic predicts the next requests. Watch what happens during bursts: newly accessed entries can displace responses that still have recurring demand. Evaluate the misses after the burst, rather than judging the policy only while traffic is concentrated.
LFU, or least frequently used, suits product or configuration caches with repeatedly accessed records and occasional requests across a broader set. Its benefit is retaining that established hot set. The trade-off appears when demand moves: historical popularity can make the cache slower to adapt. Compare behavior during workload changes as well as steady traffic.
TTL-based selection makes sense for validation responses when shorter remaining retention windows correspond to entries you can afford to lose first. Check that assumption against application behavior. An entry near expiration may still avoid an expensive repeat validation, so remaining lifetime alone doesn't establish its value. The policy documentation explains these selection signals.
Random selection is reasonable when neither access history nor remaining lifetime usefully predicts demand. Accept the consequence explicitly: frequently requested entries can disappear alongside cold ones. The application must tolerate either loss.
A session store requires a different decision from a recomputable response cache. If losing a session disrupts active work, choosing a more suitable ranking signal does not solve the data-safety problem.
Treat workload matching as a testable hypothesis. Compare cache misses and the resulting application work under representative traffic, including bursts and shifts in demand. A policy earns its place by keeping acceptable losses affordable.
Eviction Is Not Expiration and TTL Is Not Protection
Expiration removes a key because its TTL has elapsed. Eviction removes a key to enforce a memory limit. The distinction matters because a TTL doesn't promise that Redis will keep a key until the clock runs out, nor does it make a key eligible under every policy.

How a volatile policy can run out of candidates
Suppose an instance holds temporary responses with TTLs alongside persistent records without them. A volatile-* policy can choose only from the temporary entries. If those eligible entries are exhausted or unavailable as candidates, Redis can't evict the persistent records under that policy. Writes that need memory can then fail, depending on the configured behavior.
This is why TTL is eligibility metadata, not data protection. A key with a TTL can be removed under memory pressure before its expiration time. A key without one can be safe from a volatile policy's selection, but that doesn't mean the overall instance will keep accepting writes.
For a dedicated cache, using allkeys-lru or allkeys-lfu can align with the fact that every value is recomputable. For an instance that also holds sessions, locks, or workflow state, don't rely on a single eviction policy to understand the business value of each key. Separate key classes into distinct instances where possible, and apply consistent TTL rules to cache entries.
A key's business role matters more than whether it happens to carry an expiration timestamp.
Test the distinction rather than inferring it from configuration. Exercise memory pressure in a controlled environment and observe whether Redis evicts the intended keys or rejects writes. That test catches a mixed-keyspace design flaw before an ordinary traffic spike does.
Tuning maxmemory and Monitoring the Right Metrics
A traffic spike can turn a cache that fits comfortably at steady state into a source of rejected writes and upstream load. Set maxmemory against the working set and memory available to Redis, leaving headroom for operating overhead and traffic variation. A tight ceiling increases churn; an oversized ceiling exposes the deployment to memory pressure outside Redis's eviction controls.
Treat the ceiling as an operational data-safety boundary.
Deployment behavior matters. Redis Cloud Active-Active databases begin eviction when an instance reaches 80% of its configured memory limit, while self-managed Redis applies the selected policy at its configured maxmemory limit. Redis documents the Active-Active threshold and self-managed behavior. Base alerts on the service's enforcement threshold rather than assuming every deployment can use its entire configured capacity before eviction starts.

Read the metrics together
used_memoryshows current Redis memory use. Compare it with the applicable enforcement threshold.used_memory_peakrecords the high-water mark and helps expose pressure hidden by a quiet sampling period.evicted_keystracks removals under memory pressure. Monitor its change over time, since the accumulated count alone doesn't describe current churn.keyspace_hitsandkeyspace_missesshow read effectiveness. Compare their rates alongside evictions to assess whether useful entries are being displaced.- Rejected writes and memory-limit errors require application-level visibility. With
noeviction, writes needing more space fail; ignored errors can make cache population failures appear silent.
For example, alert when eviction activity rises while the hit rate falls over the same observation window. Confirm the impact with application latency and upstream request volume before paging: that combination can indicate a working set that no longer fits, but changing traffic patterns also affect hits.
Memory graphs alone won't expose ignored write errors. Track cache-write failures alongside read performance, including for REST response caches such as the implementation described in TaxID's Redis REST API caching guide.
Production Walkthrough Tuning a Validation Cache
Consider a VAT-validation cache in a checkout flow. The application caches a validation response for 24 hours and wants cached lookups to return in under 10ms. Those targets describe this example, not a universal Redis guarantee. The cache exists to reduce repeat calls to an upstream SOAP service that can become unavailable, so cached responses are useful but safely recomputable.
For a dedicated cache containing only those responses, allkeys-lru is a sensible starting policy: every key is disposable cache data, so any key can be considered if memory pressure requires it. Set a maxmemory ceiling that leaves headroom above the steady-state working set. Don't guess from key count alone; serialized response sizes and the actual access pattern determine whether that working set fits.
Make the failure behavior explicit
Give cache entries an intentional TTL that matches the freshness requirement. That defines normal expiration, while the selected eviction policy handles pressure before entries expire. Because the instance is dedicated to cache data, an all-keys policy avoids depending on every key having expiration metadata to be eligible.
In Grafana, chart used_memory, used_memory_peak, evicted_keys, keyspace_hits, and keyspace_misses together with application latency and upstream errors. Alert on combinations that show impact: memory pressure with rising evictions and worsening hit behavior, or a rise in rejected writes. A raw eviction count without request context can't tell you whether the cache is functioning acceptably.
For the application design around VAT validation and caching, TaxID's VAT API rate-limiting and caching use case describes a related workflow. The important operational practice is to test the Redis behavior independently: increase cache load in a controlled environment, observe which keys disappear, and verify that misses trigger a safe fallback rather than causing checkout to fail closed.
Operational Playbook for Stable Redis Caching
Use a decision tree that starts with the data, not the policy name.
- Dedicated cache: If every value is disposable, choose
allkeys-lruorallkeys-lfubased on whether recency or frequency better reflects demand. Set a deliberate memory ceiling and watch memory use, evictions, hit rate, and application latency. - Mixed workload: If the instance combines cache entries with state that must survive, separate those roles. A
volatile-*policy won't evict keys without TTLs, and an all-keys policy may remove data the application needs. - Write-strict store: If automatic eviction is unacceptable,
noevictionmakes writes fail when they require more memory. The application must detect and handle that failure rather than treating Redis as though it always accepts writes.
Run controlled tests for the failure modes your design permits. First, put persistent and expiring keys in a test instance and confirm what happens when volatile candidates are no longer available. Next, exercise the write path under noeviction and confirm rejected writes surface clearly to application monitoring. Finally, check the managed service's actual eviction trigger so dashboards and alerts match its enforcement model.
Runbook check: A passing test should show the intended keys being removed, misses recovering through the application, and write failures producing visible alerts rather than silent data loss.
Keep a short record of the chosen policy, the key classes stored in the instance, what the application does after eviction, and who owns memory alerts. Revisit that record when the workload or keyspace changes. For broader cache design decisions, see Redis caching strategies.
TaxID provides a developer-first API for VAT and company ID validation, with Redis-backed caching for repeat lookups and machine-readable errors for upstream failures. If VIES validation is part of your checkout or billing path, visit TaxID to review the API and its documentation.