Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Redis Eviction Policies

Learn how Redis manages memory by evicting keys when maxmemory is reached. Explore all eviction policies from noeviction to volatile-lru and allkeys-lfu, and choose the right one for your use case.

Focus: Redis eviction policies

Sponsored

Picture this: your Redis server is humming along, serving cached data at lightning speed, and then — boom — it runs out of memory. What happens next? Depending on your configuration, Redis might crash, reject writes, or silently delete your most critical keys. Understanding Redis eviction policies isn't a dusty theoretical exercise; it's the difference between a resilient caching layer and a production meltdown at 3 AM. By the end of this lesson, you'll know exactly how each policy works and which one to pick for your workload.

The problem this lesson solves

Every byte of data in Redis lives in RAM. While memory is fast, it's also finite. You set maxmemory (say, 1 GB), and your application fills it up faster than expected — maybe a spike in traffic, a memory leak in your code, or just more data than you planned for. When the limit is hit, Redis has to decide: deny new writes, remove some existing data, or panic and crash.

This isn't a hypothetical. Many developers discover eviction policies the hard way when their cache stops accepting writes or, worse, silently drops the session keys that keep users logged in. The core problem is that without an eviction policy, Redis defaults to noeviction, which blocks write commands when memory is full. That can cause application errors, timeouts, and data loss.

Pro tip: Always set a maxmemory limit and a deliberate eviction policy. Ignoring it is a ticking time bomb in production.

Core concept / mental model

Imagine a busy coffee shop with a fixed number of seats (maxmemory). When all seats are taken, new customers (write requests) can't sit down. The shop has a few options:

  • noeviction – Turn away anyone new; existing customers stay (writes fail).
  • allkeys-lru – Kick out the customer who hasn't visited in the longest time, regardless of which table they're at.
  • allkeys-lfu – Kick out the customer who orders the least (least frequently used).
  • volatile-ttl – Kick out the customer whose reservation (TTL) is about to expire, but only if they have a reservation.
  • volatile-lru – Same as allkeys-lru, but only consider customers who have a reservation (keys with TTL set).
  • volatile-random – Randomly select a customer with a reservation to leave.
  • allkeys-random – Randomly select any customer to leave.

Each policy is a trade-off between predictability, performance, and data retention. The term volatile in Redis means keys that have an expiration time set. All other keys (persistent ones) are never evicted under volatile policies.

Key definitions

  • Eviction: The act of removing a key to free memory, performed when maxmemory is exceeded.
  • LRU (Least Recently Used): Evicts the key that hasn't been accessed for the longest time. Efficient and popular for caching.
  • LFU (Least Frequently Used): Evicts the key with the lowest access frequency. Better for workloads with hot and cold data patterns.
  • TTL (Time To Live): The expiration time set on a key. Redis monitors TTL and can evict the key with the shortest remaining life (volatile-ttl).
  • noeviction: The default policy. When memory is full, any write command (SET, LPUSH, etc.) returns an error.

How it works step by step

Redis eviction is not a background thread — it happens synchronously on the thread that triggers the memory limit. Here's the sequence:

  1. A write command arrives (e.g., SET user:1001 data).
  2. Redis checks the current memory usage against maxmemory.
  3. If memory is already at or above the limit, Redis selects one or more keys to evict based on the configured policy.
  4. The selected keys are deleted from the keyspace, and memory is freed.
  5. The write command proceeds.

Sampling, not scanning

To keep eviction fast, Redis does not scan the entire keyspace. Instead, it uses a sample-based approach:

  • For LRU, LFU, and TTL policies, Redis samples maxmemory-samples keys (default 5) from the relevant pool (all keys or volatile keys).
  • It evicts the best candidate among those samples.
  • Larger sample sizes improve eviction quality but increase CPU cost.

Pro tip: Increase maxmemory-samples to 10 for more accurate eviction decisions, especially with large datasets.

The eviction pool

Redis maintains an eviction pool – a sorted list of candidate keys from previous samples. This reduces the number of keys it needs to sample on each eviction, making the process more efficient.

Hands-on walkthrough

Let's bring this to life with practical examples. We'll use redis-cli to configure and observe eviction in action.

Example 1: noeviction (the default)

# Connect to Redis
redis-cli

# Check current maxmemory and eviction policy
CONFIG GET maxmemory
CONFIG GET maxmemory-policy

# Set a low maxmemory to force eviction quickly
CONFIG SET maxmemory 1mb
CONFIG SET maxmemory-policy noeviction

# Fill memory with data
SET key1 "A" * 1000000  # This will work

# Next write will fail
SET key2 "B"
# Output: (error) OOM command not allowed when used memory > 'maxmemory'

Expected output: The second SET fails with an out-of-memory error. Writes are blocked.

Example 2: allkeys-lru

# Switch to allkeys-lru
CONFIG SET maxmemory-policy allkeys-lru

# Add keys with different access patterns
SET alpha "first"
SET beta "second"
SET gamma "third"

# Access some keys frequently (simulating hot data)
GET alpha
GET alpha
GET beta

# Trigger eviction by adding more data
SET delta "fourth"
SET epsilon "fifth"

# Check which keys survived
KEYS *
# Likely output: alpha, beta, epsilon (gamma and delta probably evicted)

Explanation: gamma was never read after creation, and delta was added just before eviction — they are the least recently used and get evicted first.

Example 3: allkeys-lfu

# Switch to LFU
CONFIG SET maxmemory-policy allkeys-lfu

# Re-populate with controlled access
SET item1 "A"
SET item2 "B"
SET item3 "C"

# Simulate access frequency
GET item1   # item1: count=1
GET item1   # item1: count=2
GET item2   # item2: count=1

# Force eviction
SET item4 "D"
SET item5 "E"

# Check survivors
MEMORY USAGE item3  # Likely evicted

Note: LFU uses a logarithmic counter that decays over time, so it's not a raw counter. item3 (never accessed) is a prime candidate for eviction.

Example 4: volatile-ttl

CONFIG SET maxmemory-policy volatile-ttl

# Create keys with different TTLs
SET temp1 "A" EX 10
SET temp2 "B" EX 60
SET temp3 "C" EX 5

# Add persistent key (no TTL) — it won't be evicted
SET persistent "D"

# Trigger eviction
SET temp4 "E" EX 20

# temp3 (TTL=5) should be evicted before others

Key insight: Only keys with an explicit TTL are candidates. The persistent key D is safe.

Compare options / when to choose what

Policy Eviction Target Best For Drawback
noeviction None Pure memory-bound use cases Writes fail; not for caching
allkeys-lru Any key (LRU) General purpose caching Can evict frequently used keys if not accessed recently
allkeys-lfu Any key (LFU) Workloads with clear hot/cold data Slightly more CPU overhead; counters decay
volatile-lru Keys with TTL (LRU) Caching with expiration guarantees Persistent keys never evicted; can still OOM
volatile-lfu Keys with TTL (LFU) Same as volatile-lru, but LFU-based Same drawbacks as volatile-lru
volatile-ttl Keys with TTL (shortest TTL first) When you want short-lived data to go first Slower eviction sampling; less accurate than LRU
allkeys-random Any key (random) When predictability of eviction doesn't matter Unpredictable; can evict important keys
volatile-random Keys with TTL (random) Niche cases Same unpredictability

Quick decision guide

  • Is your Redis a cache?allkeys-lru or allkeys-lfu
  • Do you have strict TTLs and want to protect persistent data?volatile-lru
  • Running critical data that must never be evicted? → Set noeviction and monitor memory closely
  • Want maximum performance?allkeys-lru is the most efficient
  • Large dataset with hot/cold pattern?allkeys-lfu often provides better hit rates

Troubleshooting & edge cases

1. "OOM command not allowed when used memory > 'maxmemory'"

Root cause: You're using noeviction policy and the memory limit is reached. Fix: Switch to an eviction policy like allkeys-lru or increase maxmemory.

2. Persistent keys being evicted unexpectedly

Root cause: You're using allkeys-lru or allkeys-lfu when you intended to protect persistent keys. Fix: Use volatile-lru instead — it only evicts keys with TTL.

3. Write commands working but memory not freeing

Root cause: The eviction process may be busy removing large keys. Redis eviction is synchronous and can block if it takes too long. Fix: Use smaller key sizes or increase maxmemory-samples for better candidate selection.

4. LFU not working as expected — hot keys get evicted

Root cause: LFU's decay time can cause recently accessed keys to lose their counter if not decayed properly. Check the lfu-decay-time configuration. Fix: Adjust lfu-decay-time (default 1 minute). A lower value decays faster. Use lfu-log-factor to control counter growth.

5. Redis uses more memory than maxmemory

Root cause: Redis has internal memory overhead that isn't counted against maxmemory. Eviction is triggered by the keys memory, not total process memory. Fix: Monitor used_memory vs used_memory_rss (resident set size). Set maxmemory conservatively (e.g., 80% of physical RAM).

What you learned & what's next

You now understand Redis eviction policies — from the default noeviction that blocks writes, to the sampling-based LRU, LFU, and TTL policies. You can explain the difference between volatile and allkeys policies, configure them dynamically via CONFIG SET, and predict the behavior when memory runs out.

Key takeaways for your next steps: - Always configure maxmemory and maxmemory-policy in production. - For caching, allkeys-lru is the safe, performant default. - For workloads with careful TTL management, volatile-lru protects persistent data. - Sampling and the eviction pool keep eviction fast, but increase maxmemory-samples for better accuracy.

In the next lesson, you'll explore Redis memory fragmentation — how to measure it, why it happens, and how activedefrag can help reclaim wasted RAM.

Practice recap

Open your Redis CLI and run CONFIG SET maxmemory 5mb followed by CONFIG SET maxmemory-policy allkeys-lru. Generate a few keys, then access some repeatedly. Add more keys until eviction occurs, then inspect which keys survived with KEYS *. Repeat with allkeys-lfu and notice the difference. This hands-on exploration will solidify how each policy decides what to keep.

Common mistakes

  • Not setting maxmemory at all, leading to Redis using all available RAM and potentially hitting OS OOM killer.
  • Using noeviction in a cache scenario and then wondering why writes fail — it's the default!
  • Mixing allkeys-lru and volatile-lru without understanding that volatile policies protect persistent keys, but can still fill memory with those keys.
  • Expecting LFU to perfectly track frequency — it uses a probabilistic counter that may decay hot keys if lfu-decay-time is too high.

Variations

  1. Instead of allkeys-lru, use allkeys-lfu for workloads where access frequency is more important than recency.
  2. For multi-tenant environments, use volatile-ttl to ensure keys with shorter TTLs are evicted first, giving longer-lived caches more time.
  3. Some Redis deployments use volatile-random for sharded clusters where LRU coordination adds overhead.

Real-world use cases

  • E-commerce session cache: Use volatile-lru to evict expired sessions while preserving product inventory keys.
  • API rate limiter: Store counters with TTL; volatile-ttl ensures oldest limits are cleaned up first.
  • Global news feed cache: allkeys-lfu keeps trending articles in memory longer than rarely accessed ones.

Key takeaways

  • Redis eviction policies control what happens when maxmemory is reached — default is noeviction (writes fail).
  • LRU (least recently used) is the most common eviction strategy and works well for general caching.
  • LFU (least frequently used) is better for workloads with clear hot/cold data patterns.
  • Volatile policies only evict keys with TTL set, protecting persistent data.
  • Eviction is sample-based and synchronous, so tune maxmemory-samples for accuracy vs. CPU.
  • Always test your eviction policy with realistic traffic patterns before deploying to production.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.