Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes
Sponsored Reserved space — layout preview until AdSense is connected
Python

Cache Eviction Policies in Redis: LRU, LFU, and More Explained

Learn how Redis cache eviction policies like LRU, LFU, and volatile-ttl work, and how to choose the right one for your Python application to keep your cache efficient under memory pressure.

July 2026 12 min read 1 views 0 hearts

When you're working with Redis as a cache, you'll eventually hit a wall—the memory limit. Redis is an in-memory data store, which means it keeps everything in RAM. And RAM, as you probably know, isn't infinite. So what happens when you set a maxmemory limit and Redis runs out of space? That's where eviction policies come in.

Think of it like a busy kitchen with limited counter space. When the counter gets full, you have to decide what to throw away to make room for new ingredients. Redis does the same thing with your cached data. The policy you choose determines which keys get the boot.

Why Eviction Policies Matter

If you're running a production application with PythonSkillset, you've probably set up Redis as a cache to speed up database queries or session storage. Without an eviction policy, Redis would just throw an error when memory fills up. That's rarely what you want. A well-chosen eviction policy keeps your cache useful even under memory pressure.

Let's walk through the most common eviction policies Redis offers, and when you'd want to use each one.

The Default: No Eviction

By default, Redis uses noeviction. This means when memory is full, any write operation that would increase memory usage returns an error. Reads still work fine. This is safe but not practical for most caching scenarios. You'd only want this if you're using Redis as a database where data loss is unacceptable.

LRU: Least Recently Used

LRU is the most popular eviction policy. It works on a simple idea: the keys you haven't touched in the longest time are the ones most likely to be evicted first.

Redis offers two flavors:

  • allkeys-lru: Evicts any key, regardless of whether it has an expiration set.
  • volatile-lru: Evicts only keys that have an expiration time (TTL) set.

LRU is great for general-purpose caching. Imagine you're running a PythonSkillset blog where you cache article previews. Older articles that nobody reads anymore will naturally get evicted first, making room for fresh content. It's a solid default choice.

But here's the catch: Redis doesn't implement a perfect LRU. That would require tracking every access timestamp, which uses too much memory. Instead, Redis uses an approximation. It samples a small pool of keys (by default 5) and evicts the oldest among them. This works well in practice, but it's not perfect.

LFU: Least Frequently Used

LFU takes a different approach. Instead of looking at when a key was last used, it looks at how often it's been used. The idea is that frequently accessed keys are more valuable than rarely accessed ones.

Redis offers two LFU variants:

  • allkeys-lfu: Evicts any key based on frequency.
  • volatile-lfu: Evicts only keys with TTLs.

LFU is particularly useful when you have a mix of hot and cold data. For example, on PythonSkillset, you might have a few popular articles that get thousands of views daily, while most articles get only occasional visits. LFU would keep those popular articles in cache while evicting the less popular ones.

But LFU has a quirk: it can suffer from "frequency aging." A key that was popular a week ago but is now dead might still have a high frequency count. Redis handles this with a decay mechanism that gradually reduces frequency over time, so old popularity doesn't lock out new content.

The Full List of Eviction Policies

Redis actually gives you eight options. Here's the complete lineup:

  • noeviction: Returns errors on write operations when memory is full.
  • allkeys-lru: Evicts the least recently used key from the entire keyspace.
  • allkeys-lfu: Evicts the least frequently used key from the entire keyspace.
  • volatile-lru: Evicts the least recently used key among those with an expiration set.
  • volatile-lfu: Evicts the least frequently used key among those with an expiration set.
  • allkeys-random: Evicts a random key from the entire keyspace.
  • volatile-random: Evicts a random key among those with an expiration set.
  • volatile-ttl: Evicts the key with the shortest remaining time to live.

When to Use Each Policy

Let's break this down with real scenarios you might face at PythonSkillset.

allkeys-lru for General Caching

This is the go-to for most caching use cases. If you're caching API responses, database query results, or rendered HTML snippets, LRU works beautifully. The assumption is that if a key hasn't been accessed recently, it's probably not needed anymore.

For example, if you cache user profile data, a user who logs in daily will keep their profile in cache. A user who hasn't visited in months will naturally get evicted. Simple and effective.

allkeys-lfu for Hot Data

LFU shines when you have a clear "hot" set of data that gets accessed far more than everything else. Think of a news website where the top story gets 90% of traffic. LRU might evict that top story if it hasn't been accessed in a few minutes during a lull, but LFU would keep it because of its high access count.

At PythonSkillset, we've seen LFU work well for caching API responses where certain endpoints are called thousands of times more than others. The frequency counter ensures that popular data stays cached even if it hasn't been accessed in the last few seconds.

volatile-ttl: The Time-Based Approach

This one is straightforward: Redis evicts keys with the shortest remaining time to live. If you set TTLs on your cache keys, this policy will clear out the ones that are about to expire anyway.

This is useful when you have a mix of short-lived and long-lived cache entries. For example, session tokens might have a 30-minute TTL, while product catalog data might have a 24-hour TTL. With volatile-ttl, Redis will evict the session tokens first, which makes sense because they're about to expire anyway.

Random Eviction: The Underdog

Random eviction sounds lazy, but it's surprisingly effective in some cases. Redis offers both allkeys-random and volatile-random. The idea is simple: when memory is full, pick a random key and evict it.

This works well when all your cached data has roughly equal value. If you're caching things like user avatars or static assets where every item is equally important, random eviction is fast and fair. It doesn't have the overhead of tracking access times or frequencies.

volatile-ttl: The Time-Sensitive Option

This policy looks at keys with expiration times and evicts the one with the shortest remaining TTL. It's useful when you have a clear hierarchy of expiration times. For example, you might cache session data with a 15-minute TTL and product details with a 1-hour TTL. Redis will evict the session data first, which makes sense because it was going to expire soon anyway.

But there's a catch: if you have many keys with the same TTL, Redis picks one randomly among them. It's not a perfect "shortest first" algorithm, but it's good enough for most cases.

How to Choose the Right Policy

There's no one-size-fits-all answer. Here's a practical guide based on what you're caching:

  • General API responses: Use allkeys-lru. It's simple and works well for most cases.
  • Content with clear popularity differences: Use allkeys-lfu. This keeps your most popular content cached.
  • Session data with TTLs: Use volatile-ttl. Sessions expire naturally, so evict the ones closest to expiration.
  • When you don't care which keys get evicted: Use allkeys-random. It's the cheapest in terms of CPU.
  • When you want to be safe: Use noeviction and handle errors in your application code.

Setting the Policy in Redis

You can set the eviction policy in your Redis configuration file or at runtime. Here's how you'd do it in your PythonSkillset application using the redis-py library:

import redis

r = redis.Redis(host='localhost', port=6379, db=0)

# Set maxmemory to 100MB
r.config_set('maxmemory', '100mb')

# Set eviction policy to allkeys-lru
r.config_set('maxmemory-policy', 'allkeys-lru')

You can also set these in your redis.conf file:

maxmemory 100mb
maxmemory-policy allkeys-lru

The Sampling Trade-off

Here's something most tutorials don't tell you: Redis doesn't scan the entire keyspace to find the best key to evict. That would be too slow. Instead, it samples a small number of keys and picks the best candidate from that sample.

The default sample size is 5 keys. You can change this with the maxmemory-samples configuration. A larger sample size gives you a more accurate eviction decision but uses more CPU. A smaller sample is faster but less precise.

For most applications, the default of 5 is fine. But if you have millions of keys and you're seeing suboptimal evictions, you might bump it up to 10 or 20. Just remember that each eviction now checks more keys, which adds latency.

Real-World Example: PythonSkillset's Caching Strategy

Let me give you a concrete example from PythonSkillset. We cache article content to reduce database load. Most articles get a few hundred views, but our top 10 articles get tens of thousands. We also cache user session data with a 30-minute TTL.

For the article cache, we use allkeys-lfu. The popular articles stay cached because they're accessed frequently. The long-tail articles get evicted when memory runs low, which is fine because they're rarely requested anyway.

For session data, we use volatile-ttl. Sessions have a natural expiration, so evicting the ones closest to expiry makes sense. If a user comes back after their session expired, they'll just get a new one.

The Performance Impact

Here's something you might not expect: eviction policies have different CPU costs. Random eviction is the cheapest because Redis just picks a key at random. LRU and LFU require sampling, which costs a tiny bit more CPU. For most applications, this difference is negligible. But if you're running Redis at massive scale with millions of keys and constant evictions, it can add up.

The maxmemory-samples setting controls how many keys Redis samples before evicting. The default is 5. If you increase it to 10 or 20, you get better eviction decisions but slightly higher CPU usage. For most PythonSkillset users, the default is fine.

Setting the Policy in Your PythonSkillset Application

Here's how you'd configure eviction in your Python code:

import redis

cache = redis.Redis(host='localhost', port=6379, decode_responses=True)

# Set max memory to 500MB
cache.config_set('maxmemory', '500mb')

# Use allkeys-lfu for frequently accessed data
cache.config_set('maxmemory-policy', 'allkeys-lfu')

You can also check what's currently set:

print(cache.config_get('maxmemory-policy'))
# Output: {'maxmemory-policy': 'allkeys-lfu'}

Which One Should You Choose?

Here's a quick decision guide:

  • You're building a general-purpose cache: Start with allkeys-lru. It's the most forgiving and works well for most workloads.
  • You have clear hot data: Use allkeys-lfu. This keeps your most popular content cached.
  • You rely heavily on TTLs: Use volatile-ttl. It complements your expiration strategy.
  • You don't care which keys get evicted: Use allkeys-random. It's the simplest and fastest.
  • You want to be safe: Use noeviction and handle the error in your code. This gives you full control.

A Practical Example

Let's say you're building a PythonSkillset feature that caches user search results. Each search query returns a list of articles. You set a TTL of 5 minutes because search results change frequently.

You'd probably use volatile-ttl here. When memory gets full, Redis evicts the search results that are closest to expiring anyway. This keeps your cache fresh and avoids evicting data that still has a long life ahead.

Here's how you'd configure it:

import redis

cache = redis.Redis(host='localhost', port=6379, decode_responses=True)
cache.config_set('maxmemory', '200mb')
cache.config_set('maxmemory-policy', 'volatile-ttl')

What About Performance?

All eviction policies have some CPU cost, but it's usually negligible. The exception is when you're constantly hitting the memory limit and evicting keys on every write. In that case, you might want to increase your maxmemory or optimize your cache usage.

Random eviction is the cheapest. LRU and LFU are slightly more expensive because they need to sample keys. But in practice, even on busy Redis instances, the overhead is tiny.

A Word of Caution

Don't set your maxmemory too low. If Redis is constantly evicting keys, you're spending more time on eviction than on serving data. Monitor your cache hit rate. If it drops below 80%, consider increasing your memory limit or optimizing what you cache.

Also, remember that eviction policies only kick in when memory is full. If you have plenty of RAM, no eviction happens at all. So the first step is always to set a reasonable maxmemory that gives your cache room to breathe.

Final Thoughts

Choosing the right eviction policy is about understanding your data access patterns. LRU is the safe bet for most applications. LFU is better when you have clear popularity differences. volatile-ttl works well with expiration-based caching. And random eviction is surprisingly effective when you don't have strong patterns.

At PythonSkillset, we've found that starting with allkeys-lru and monitoring cache hit rates is a good approach. If you see that your most popular data is getting evicted too often, switch to allkeys-lfu. If you're using TTLs heavily, try volatile-ttl.

The key is to monitor and adjust. Redis gives you the tools—you just need to pick the right one for your workload.

Comments

Questions, corrections, and tips stay visible for everyone reading this page.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.