Redis cache: how it works, and Redis vs Memcached

Why Redis is fast, how TTLs and eviction policies work, how to size memory, when persistence matters for a cache, and how Redis compares with Memcached.

9 min read
On this page 8 sections
  1. What Redis is
  2. Why Redis is fast
  3. TTLs and eviction policies
  4. Sizing memory
  5. Persistence and replication
  6. Redis vs Memcached
  7. Key takeaways
  8. Frequently asked questions

Redis works as a cache by keeping keys and values in RAM and answering simple commands such as GET and SET over the network, without the parsing, planning and disk reads a database query involves. You give each cached key a time to live (TTL), and when memory fills up, Redis evicts keys according to the policy you choose, such as least recently used. Memcached does the same core job more simply; Redis adds data structures, persistence and replication.

What Redis is

Redis is an in-memory data store. Values can be plain strings, which is how most caches use it, or structures such as hashes, lists, sets and sorted sets, each with commands that work on the structure directly. That is why the same server often ends up doing several jobs on a learning platform: caching course pages, holding sessions, counting login attempts for rate limiting, keeping live leaderboards in sorted sets and passing messages between processes.

So is Redis a database or a cache? Both, depending on how you configure it. With persistence and replication it can be a primary store for data that suits it. As a cache, it holds copies of data whose real home is your database, and losing a key costs a rebuild, not data.

Why Redis is fast

  • Everything is in memory. Reads never wait for a disk.

  • The work per command is small and predictable. Each command's time complexity is documented, and GET and SET run in constant time.

  • One thread runs the commands. Redis serves clients from a mostly single-threaded event loop, using I/O multiplexing to juggle thousands of connections. There are no locks to contend for and commands execute one at a time, so each is atomic. Optional I/O threads can take over socket reads and writes on busy servers.

  • The protocol is light, and clients can pipeline many commands into one round trip.

The single thread has a flip side, spelled out in Redis's latency documentation: one slow command makes every client wait. The classic mistake is running KEYS "course:*" in production to find keys to delete, which walks the entire keyspace while everything else queues behind it. Use SCAN, or design keys so you never need to search for them, for example with versioned keys.

TTLs and eviction policies

Two separate mechanisms remove keys. Expiry removes a key when its TTL runs out. Eviction removes keys when Redis hits its memory limit, whether or not they have expired.

SET course:42:outline "{...}" EX 3600    # store with a one-hour TTL
TTL course:42:outline                     # seconds remaining
CONFIG SET maxmemory 1gb
CONFIG SET maxmemory-policy allkeys-lru
INFO stats                                # keyspace_hits, keyspace_misses, evicted_keys

Redis expires keys in two ways: passively, when a client touches an expired key, and actively, by sampling keys that have a TTL and deleting the expired ones. An expired key disappears from view immediately, even if its memory is reclaimed a little later.

Eviction is controlled by maxmemory and maxmemory-policy. Two defaults matter: on 64-bit systems maxmemory is 0, meaning no limit, and the default policy is noeviction, which makes Redis return errors on writes once memory is full. Neither suits a cache.

PolicyEvictsUse when
allkeys-lruLeast recently used keysThe usual choice for a pure cache
allkeys-lfuLeast frequently used keysA small set of keys is hot for long periods, such as the current test series
volatile-lru, volatile-lfuThe same, but only among keys with a TTLOne instance holds both cache keys and keys that must stay
volatile-ttlKeys closest to expiryYour TTLs already express priority
allkeys-random, volatile-randomRandom keysAll keys are accessed about equally
noeviction (default)Nothing; writes failRedis is a primary store, not a cache

Recent releases also add LRM (least recently modified) variants. Redis's LRU and LFU are approximations: it samples a few keys (five by default, set by maxmemory-samples) and evicts the best candidate, which the eviction documentation shows is close to true LRU in practice. Check the hit ratio as keyspace_hits divided by hits plus misses, and watch evicted_keys: a high eviction count alongside a low hit ratio usually means the cache is too small for its working set, or the policy is evicting the wrong keys.

One warning: don't keep sessions and cache entries in one instance under allkeys-lru, or a traffic spike can evict sessions and log students out mid-test. Redis's own docs suggest two separate instances; a volatile policy, with TTLs only on cache keys, is the fallback.

Sizing memory

Estimate from what you will store, then measure. Here is an illustrative platform with 1.5 lakh registered students and 30,000 active at peak:

WhatKeysSize eachTotal
Course outlines2,0008 kB16 MB
Dashboard summaries for active students30,0003 kB90 MB
Sessions (kept in a separate instance)1,00,0001 kB100 MB
Per-key overhead, all instancesAbout 1.3 lakh keysAbout 100 bytes13 MB

The overhead line comes from Redis's FAQ, which measures about 85 MB for a million small string keys on a 64-bit build, or roughly 85 bytes each including tiny values. That puts this cache at roughly 110 MB and the session store at about the same. Then add headroom: Redis recommends leaving memory free for replication and persistence buffers, and saving a snapshot forks the process, so memory pages that change during the save get copied. Set maxmemory well below the machine's RAM rather than equal to it, then check real numbers with INFO memory and MEMORY USAGE on sample keys.

Persistence and replication

A pure cache doesn't need persistence for durability, because the database has the real data. It can still be worth having, for a different reason: a Redis that restarts empty sends every request to the database at once, which is a cache stampede on a grand scale.

  • RDB snapshots write a compact point-in-time file at intervals. Unless configured otherwise, Redis saves after an hour if at least one key changed, after five minutes if 100 changed, and after a minute if 10,000 changed. Good for warm restarts and backups.

  • AOF (append-only file) logs every write and replays it on restart. The default fsync policy, everysec, can lose about a second of writes in a crash. Use it when Redis holds data you'd miss, such as sessions or live leaderboards.

  • No persistence is common for caches that can refill quickly, and you can combine RDB with AOF.

Replication is asynchronous by default: a replica receives writes shortly after the primary acknowledges them, and the WAIT command can make a client wait for replicas when needed. Replicas give you failover with Redis Sentinel or Cluster, and extra read capacity; Django's Redis backend, for example, can write to the first server in its list and read from the rest.

Redis vs Memcached

RedisMemcached
Data modelStrings plus hashes, lists, sets, sorted sets, streams and moreStrings (opaque blobs) only
ThreadsCommands on one thread; optional I/O threadsMulti-threaded; 4 worker threads by default
Largest value512 MB per string1 MB by default, adjustable
PersistenceRDB snapshots, AOF, or noneNo durable persistence; a crashed server comes back empty
ReplicationBuilt in, with Sentinel and Cluster for failover and shardingNot built in; clients spread keys across servers
EvictionChoice of LRU, LFU, TTL-based, random or noneLRU
LicenceRedis 8 onwards: RSALv2, SSPLv1 or AGPLv3, your choiceBSD

Choose Memcached when you want nothing but a fast, simple cache for strings and can live with losing it when a server goes down. Its threads make good use of a large multi-core machine without running several instances. Choose Redis when you want anything more: leaderboards, rate limiting, locks, queues, sessions, or a cache that survives restarts. For most Django or Node apps that is Redis, because it replaces several components at once.

Licensing is the other axis. Redis versions up to 7.2 were BSD-licensed; 7.4 moved to RSALv2 or SSPLv1, and Redis 8 added AGPLv3 as a third option, according to Redis's licence page. Valkey, a fork of the BSD-licensed Redis code backed by the Linux Foundation, remains BSD-licensed and speaks the same protocol. Managed cloud caches may run either, so check which you're getting.

Key takeaways

  • Redis is an in-memory data store; as a cache, it holds copies whose real home is your database.

  • It is fast because data lives in RAM and a single thread runs small, predictable commands, but one slow command such as KEYS blocks everyone.

  • Set maxmemory and an eviction policy such as allkeys-lru; the defaults (no limit, noeviction) don't suit a cache.

  • Keep sessions and evictable cache entries in separate instances, and size memory from your key counts plus headroom for forks and buffers.

  • Pick Memcached for a plain multi-threaded string cache; pick Redis, or Valkey, when you need data structures, persistence or replication.

How you fill and update the cache is a separate decision; see caching strategies for cache-aside and write-through, Django caching for the framework side, and rate limiting with Redis for counters.

Frequently asked questions

Is Redis a database or cache?

It can be either. Redis is an in-memory data store that can persist to disk with snapshots or an append-only log and replicate to other servers, so it can act as a primary database for data that suits a key-value model. Most teams use it as a cache in front of a relational database such as PostgreSQL, with TTLs and an eviction policy, where losing a key only means rebuilding it.

Does Redis store data in RAM?

Yes. Redis keeps the whole dataset in memory and serves every read from RAM, which is why it is fast and why memory is its main cost. Disk is used only for persistence: RDB snapshots and the append-only file let it reload data after a restart. Redis has no feature for datasets larger than RAM in its open-source edition, so plan memory and eviction carefully.

Why Redis is single threaded?

Running commands on one thread keeps Redis simple and predictable: no locks, no contention, and every command is atomic. For cache workloads the bottleneck is usually memory or network, not CPU, so one core serving small commands goes a long way. Redis does use extra threads for background work and, optionally, socket I/O, and you can run several instances or a cluster to use more cores.

Why Redis over Memcached?

Choose Redis when you need more than a simple string cache. Its data structures handle leaderboards, counters, rate limits, locks and queues natively; it can persist data so a restart doesn't mean a cold cache; and it replicates for failover. Memcached remains a good fit for a plain, multi-threaded cache of opaque values. Many teams pick Redis simply to run one system instead of two.

Share this article

Looking for something else?

Talk to Us