Özer Cem KELAHMETKELAHMET
Tools · Databases and sync

Redis

Redis is a very fast in-memory key-value store with data structures, caching and pub-sub. Learn how it works and how it supports tabular models.

Overview

Redis is an in-memory data store. It keeps data in RAM and serves it in well under a millisecond in most cases. It is more than a simple key-value cache: values can be strings, lists, sets, sorted sets, hashes, streams, bitmaps, and more, and Redis offers commands that work directly on those structures.

Teams use it for caching, session storage, rate limiting, leaderboards, queues, counters, and real-time messaging. It can persist data to disk, replicate to other servers, and scale out with clustering. It is not meant to be the main store for huge historical data sets, because RAM is more expensive per byte than disk. This page explains how Redis works, how it compares with other stores, and how it relates to tabular foundation models, which learn from raw tables. In that picture, Redis is the fast lane: it serves small, fresh slices of tabular data and results at low latency. For the model side, see /model/research.

What it is

Redis stands for Remote Dictionary Server. It is a server that you reach over the network with a simple text-based protocol. You send a command such as SET or GET, and it replies. Because most commands are tiny operations on data already in memory, they finish very fast.

Main traits:

  • In-memory storage. Data lives in RAM for speed.
  • Rich data structures. Each has its own set of atomic commands.
  • Single-threaded command execution at its core, with extra threads for network and background work. This makes each command atomic without locks.
  • Optional persistence. Snapshots and an append-only log can save data to disk.
  • Replication. Replicas copy a primary and can serve reads.
  • Automatic failover with a sentinel process, and sharding with a cluster mode.
  • Pub-sub and streams for messaging.
  • Expiry. Any key can have a time to live.
  • Scripting and modules for extra features.

Everyday analogy

A database on disk is like a warehouse across town: everything is there, but each trip takes time. Redis is the desk drawer next to you. It holds less, but whatever you need is within arm's reach. You keep in the drawer the papers you use all day, and you throw them out when they go stale.

Where it came from

Redis was created around 2009 by a developer who needed a faster way to handle real-time web statistics. The idea was a server that exposes data structures, not just blobs of bytes. It grew quickly through open source, and became one of the most widely used data stores for caching and real-time work. Over the years it has added replication, sentinel, cluster mode, streams, and a module system. Licensing and governance of the project have changed over time, and several compatible forks and alternatives exist, so check current terms for the version you plan to use.

The idea of an in-memory cache is older, with systems such as memcached being popular earlier. Redis went further by adding structures, persistence, and replication.

How it works

Step 1: Commands over a simple protocol

A client opens a connection and sends commands. The protocol is simple, so clients exist for nearly every language. Commands can be sent one at a time, in a pipeline of many without waiting for replies, or in a transaction block.

text
SET user:42:name "Ada"
GET user:42:name
EXPIRE user:42:name 3600
INCR page:home:views

Step 2: Data structures

Each key holds a value of one type, and each type has commands built for it.

Type What it is Typical use
String Bytes, text, or a number Cache values, counters
Hash A map of field to value An object such as a user profile
List Ordered items Simple queues, recent items
Set Unique unordered items Tags, unique visitors
Sorted set Unique items with a score Leaderboards, time-ordered indexes
Stream An append-only log with groups Event pipelines, message queues
Bitmap Bit-level operations on strings Daily active flags
HyperLogLog Approximate distinct counts Counting unique users cheaply
Geospatial Items by longitude and latitude Nearby lookups

Analogy: a plain key-value store is a coat check, one ticket for one coat. Redis is a coat check that also knows how to keep a sorted list of the ten best coats, or count how many different people visited today.

Step 3: Why it is fast

  • Data is in RAM, which is orders of magnitude faster than disk.
  • Compact in-memory formats and efficient structures keep operations cheap.
  • Commands are atomic and executed one after another on one thread, so there is no lock contention.
  • Pipelining sends many commands per network trip.

Step 4: Persistence options

Redis can write data to disk in two ways, alone or together.

  1. Snapshots. At intervals, the server saves a point-in-time copy of the whole data set. Restarts are quick, but changes since the last snapshot can be lost.
  2. Append-only file. Each write command is appended to a log, which is replayed on restart. You can choose how often it is flushed to disk, trading speed for safety.

If Redis is used only as a cache, you may turn persistence off entirely.

Step 5: Expiry and eviction

Keys can have a time to live. When memory is full, a policy decides what to remove, such as the least recently used keys or the least frequently used keys. Picking the right policy is key to using Redis as a cache.

Step 6: Replication and failover

A primary sends its stream of writes to replicas. If the primary fails, a sentinel group can promote a replica and tell clients where to connect. Replication is asynchronous by default, so a failover can lose the latest few writes.

Step 7: Clustering

In cluster mode, the key space is divided into a fixed number of hash slots spread across nodes. Each key maps to a slot by a hash of its name. Clients learn the map and talk to the right node. To keep related keys on the same node, you can use hash tags in key names.

Step 8: Pub-sub and streams

Pub-sub lets publishers send messages to channels, and subscribers receive them live, but messages are not stored. Streams store entries in an append-only log, with consumer groups so that several workers can share the work and acknowledge what they handled. Streams give you durable, replayable event flow in a simple form.

Key concepts and terms

Term Meaning
Key The name under which a value is stored
Value The data, of a given type
TTL Time before a key expires
Eviction policy Rule for removing keys when memory is full
Snapshot A point-in-time copy of data saved to disk
Append-only file A log of write commands for recovery
Replica A server that copies a primary
Sentinel A process that monitors and fails over
Cluster Multiple nodes splitting the key space by hash slots
Hash slot One of the fixed buckets of the key space
Pipeline Sending many commands without waiting for each reply
Transaction A queued block of commands executed together
Lua script Server-side logic that runs atomically
Stream Append-only log with consumer groups
Pub-sub Live messaging with no storage
Cache hit ratio Share of requests served from the cache

A worked example

We will build a cache, a counter, a leaderboard, and a small feature store for a model.

Cache-aside pattern

The usual caching pattern is cache-aside. The application first looks in Redis. If the value is missing, it loads from the main database, writes to Redis with a TTL, and returns it.

python
import json
import redis

r = redis.Redis(host="example.internal", port=6379, decode_responses=True)

def get_profile(user_id, db):
    key = f"profile:{user_id}"
    cached = r.get(key)
    if cached is not None:
        return json.loads(cached)
    profile = db.load_profile(user_id)          # slow path
    r.set(key, json.dumps(profile), ex=600)     # keep for 10 minutes
    return profile

Rate limiting with a counter

python
def allow_request(user_id, limit=100, window=60):
    key = f"rate:{user_id}"
    count = r.incr(key)
    if count == 1:
        r.expire(key, window)
    return count <= limit

Each call raises the count. The first call sets a one-minute timer. After the minute, the key vanishes and counting starts again.

A leaderboard with a sorted set

text
ZADD scores 1500 "alice"
ZADD scores 1720 "bob"
ZINCRBY scores 50 "alice"
ZREVRANGE scores 0 2 WITHSCORES

The sorted set keeps members ordered by score, so the top three come back in one command.

A simple online feature store for a tabular model

A model that scores a user at request time needs the latest summary features for that user. These can be computed offline in an analytics store and loaded into Redis hashes keyed by user.

python
features = {
    "n_events_30d": 128,
    "avg_duration": 41.7,
    "pricing_views": 3,
    "last_seen_epoch": 1772600000,
}
r.hset("feat:user:42", mapping=features)
r.expire("feat:user:42", 86400)

row = r.hgetall("feat:user:42")
print(row)

At request time, the scoring service fetches the hash, builds one row, and calls the model. Because the hash is small and in memory, the lookup takes a fraction of a millisecond plus network time. The offline job refreshes the hashes on a schedule, and the TTL ensures that stale features do not live forever.

What to check

  1. Does every feature hash have the same set of fields? Missing fields should be treated as missing values, not as zero.
  2. Are numbers stored as strings? Redis stores hash values as strings, so your code must convert types back.
  3. Are the offline and online values computed by the same logic? Differences between the two paths cause training and serving skew.
  4. Is there a version in the key or in a field, so that you can roll back feature definitions?

Memory sizing by example

Memory planning is the most common practical question, so here is a rough walk-through.

  • Suppose you cache 5 million feature hashes, each with 8 fields.
  • Each field name and value might take about 20 bytes, so a hash holds around 160 bytes of payload.
  • Add per-key overhead, often around 50 to 100 bytes, plus allocator overhead.
  • A rough total is 5 million x 300 bytes, or about 1.5 GB.
  • Leave headroom for background saves and growth, so plan for roughly double that.

Short field names save real memory at this scale, but readable names are worth some cost. A common compromise is to store a compact array or JSON string per row when you always read the whole row at once.

Hash versus JSON string for a feature row

Choice Good when Watch out for
Hash with fields You read or update single fields often Per-field memory overhead, string-only values
JSON string You always read the whole row Rewriting the entire value on a small change
Packed binary Memory is tight and the schema is fixed Harder debugging and versioning

For serving a tabular model, the whole row is read together almost every time, so a single compact value under one key is often simplest and fastest. Keep a schema version in the value so that readers can detect old layouts.

Atomic updates with scripts and transactions

Because commands run one at a time, a small Lua script runs without interruption. This is useful when you must read and then write based on what you read, such as a token bucket.

text
local current = redis.call("GET", KEYS[1])
if not current then
  redis.call("SET", KEYS[1], ARGV[1], "EX", ARGV[2])
  return 1
end
return 0

The script above sets a key only if it does not exist and gives it an expiry, all in one atomic step. For plain cases, the SET command with the NX and EX options does the same without a script.

Reading about latency honestly

Typical Redis latency is dominated by the network round trip, not by the command itself. If your scoring service sits in a different region from Redis, the lookup can cost far more than the model call. Place the cache close to the service, measure latency percentiles and not only averages, and watch for slow outliers caused by large keys or background saves.

Strengths and limitations

Strengths

  • Extremely low latency and high throughput.
  • Rich structures with atomic operations.
  • Simple to learn and to run.
  • Built-in expiry makes caching natural.
  • Replication, failover, and clustering are available.
  • Streams, pub-sub, and scripting extend it to messaging and logic.
  • Supported by clients in nearly every language.

Limitations

  • Capacity is bounded by memory, and memory costs more than disk.
  • Persistence is weaker than in a database built around durability, and failover can lose recent writes.
  • No general query language, no joins, and limited secondary indexing without modules.
  • Large keys and slow commands can block the single command thread.
  • Cluster mode restricts multi-key operations to keys in the same slot.
  • Data modeling is manual: you design keys and structures by hand.
  • Not suited as the only copy of critical data unless you invest in persistence and replication design.

How it compares with alternatives

System Type Best at Weak at
Redis In-memory structures Sub-millisecond reads, caches, counters, queues Large historical data, rich queries
MongoDB Document store Persistent flexible documents with rich queries Microsecond-scale caching
Cassandra Wide-column Durable write scale across regions Low-latency complex structures
PostgreSQL Relational Transactions, joins, durable truth Raw cache speed
Elasticsearch Search engine Text search and aggregation Simple counters and caches
ClickHouse Column OLAP Large scans and aggregations Point lookups at tiny latency
Kafka Connect based pipelines Streaming integration Moving data between systems Being a store itself

A typical stack places Redis in front of a durable database to absorb reads, and next to a queue or stream to handle bursts.

Role in tabular foundation models

A tabular foundation model reads rows and columns of mixed types, copes with missing values and unclear column names, and can predict in context from labeled example rows, as described at /model/architecture. Redis is not a place to store training sets, but it plays several useful roles around such a model in production: serving features, caching predictions, holding context rows, and coordinating work.

Row and column structure

A Redis hash is a natural fit for one row of a table: field names are column names, and values are cell values. A key such as feat:user:42 names the row. For a batch of rows, you can use many hashes, or a stream where each entry is one row. Redis does not enforce a schema, so your code must keep rows consistent with the columns the model expects.

Mixed types

Redis stores strings and a few numeric forms. A row with floats, integers, categories, and dates must be encoded and decoded by the client. Keep a single, documented encoding for each column, for example ISO text for dates and plain decimal text for numbers. Mismatched decoding is a common cause of silent errors at serving time.

Missing values

A missing field in a hash is simply absent. In training data, the same cell may have been null, and the model learned from that pattern. At serving time, absent fields must map to the same missing marker the model saw in training. Do not default to zero. Also consider an expired key: if a feature hash has expired, the whole row is missing, and the service should have a clear fallback, such as asking the offline store or using a model that can handle fully missing context.

No column names

If a model is given columns without meaningful names, the order of values matters. When you build a row from a hash, always assemble values in a fixed column order, taken from a schema stored with the model version. Do not rely on the order in which a hash returns fields.

Pre-training and offline data

Redis is not used for pre-training. Pre-training on synthetic or large real collections of tables happens offline on files and analytical stores. Redis comes in at the other end of the chain, where trained or pre-trained models are used for fast predictions.

In-context learning

A tabular foundation model that learns in context needs a small table of labeled example rows at request time. Redis can hold ready-made context sets. For example, for each segment or tenant, store a list or stream of recent labeled rows, and fetch the latest few dozen when a request arrives. A sorted set scored by timestamp can keep only the most recent rows, and a trim command can cap the size. This makes context retrieval very fast and keeps the context fresh.

text
XADD ctx:segment:7 MAXLEN ~ 500 * f1 3.2 f2 "red" label 1
XREVRANGE ctx:segment:7 + - COUNT 64

The first command appends a labeled row and keeps about 500 entries. The second reads the latest 64 rows to form the prompt table.

Continual learning

Online systems often update small statistics as events arrive, such as running counts, running means, or recent windows. Redis counters, sorted sets, and streams are well suited to this. They do not retrain a model, but they keep the inputs fresh so that a pre-trained model that reads context stays current without retraining. Periodically, a batch job can read the stream, build a new offline slice, and evaluate drift.

Imputation

Imputation at request time must be fast. Simple strategies, such as using a stored column median or the most common category, can be kept in a hash per model version and read in the same round trip as the features. More advanced imputation is usually done by the model or in the offline pipeline. Keep a flag per cell so that you know which values were imputed.

Anomaly detection

Redis suits streaming anomaly checks because counters and sliding windows are cheap. Sorted sets can keep recent events per entity, so a service can compute a quick rate or spread. Model-based scores can be cached for a short time, and anomaly alerts can be published to a channel for other services. For heavy history analysis, use an analytical store such as ClickHouse instead.

Sector and semantic classification

When a table or a column has already been classified by meaning or sector, the result is small and reused often. Redis is an ideal cache for such results, keyed by a hash of the column profile or table fingerprint. The next time the same table shape appears, the answer returns instantly without calling a model. Set a TTL, or a version in the key, so that results update when the classifier changes.

Vectors and retrieval

Modern Redis versions and modules can store vectors and run similarity search. This can help pick context rows by similarity. For larger scale or richer filtering, dedicated systems such as Qdrant or Milvus are common, and the idea of mixing keyword and vector search is covered under hybrid search. For benchmark context, see /model/benchmarks.

Practical guidance and best practices

Key design

  • Use readable, structured key names with colons, such as feat:user:42.
  • Include a version where meaning may change, such as feat:v3:user:42.
  • Keep keys short but clear, since many keys add up in memory.
  • Use hash tags in cluster mode only when you need multi-key operations on the same slot.
  • Avoid very large values. Split big objects.

Caching

  • Set a TTL on every cache key.
  • Add a little random jitter to TTLs so that many keys do not expire at once.
  • Pick an eviction policy that fits, usually least recently used or least frequently used.
  • Guard against cache stampede, where many requests rebuild the same missing value, with a short lock or request coalescing.
  • Measure the hit ratio, and tune what you cache based on it.

Persistence and safety

  • Decide if Redis is a cache or a store. Design for the answer.
  • If it is a cache, turn off persistence or accept loss on restart.
  • If it holds important data, enable the append-only file and set a sensible flush policy.
  • Use replicas and failover, and know that asynchronous replication can lose the last writes.
  • Never expose Redis directly to the internet. Use authentication, network limits, and encryption in transit.

Performance

  • Use pipelining to reduce round trips.
  • Avoid commands that scan the whole key space in production. Use incremental scan commands instead.
  • Watch for slow commands on large structures, since they block other clients.
  • Monitor memory fragmentation, evictions, connected clients, and latency.
  • Keep the data set well below the machine's memory to leave room for background saves.

Serving features to models

  • Compute features offline with the same code used for training, then load them to Redis.
  • Store a schema and column order with each feature version.
  • Treat absent keys and absent fields as missing values, not zeros.
  • Set TTLs that match how fresh features must be.
  • Log the features used for each prediction, so you can debug and retrain.
  • Add a fallback path for cache misses.

Production readiness checklist

  1. Decide if the instance is a cache or a store, and write it down.
  2. Set a memory limit and an eviction policy.
  3. Configure persistence to match that decision.
  4. Run at least one replica and test failover.
  5. Turn on authentication and restrict the network.
  6. Add monitoring for memory, evictions, latency, and replication lag.
  7. Set TTLs on all cache keys and add jitter.
  8. Review key names and sizes with a sample scan.
  9. Load test with realistic key counts and request rates.
  10. Document the fallback behavior when Redis is unavailable.

Designing the fallback

A cache should never be a hard dependency unless you accept outages. When Redis is down or slow, the service can:

  • Read from the main database and accept higher latency.
  • Serve a default prediction with a clear flag.
  • Return an error quickly, rather than waiting on a long timeout.

Set short client timeouts and use circuit breakers so a sick cache does not drag down the whole service. For a model service, decide ahead of time what to do when features are missing, and test that path.

Choosing a data structure quickly

You need Reach for
Cache one object by id String or hash with a TTL
Count events String counter with INCR
Count unique items approximately HyperLogLog
Count unique items exactly Set
Top N by score Sorted set
Recent N items List with trim, or stream with a max length
Durable event log with workers Stream with consumer groups
Daily yes or no flags for many ids Bitmap
Items near a location Geospatial index
Short-lived lock String with NX and EX

Walk down this table before you invent a clever encoding. A fitting structure usually makes the code shorter and the memory use smaller.

Monitoring signals worth alerting on

  • Memory used close to the limit.
  • Sudden growth in evicted keys.
  • Rising replication lag.
  • A falling cache hit ratio.
  • Latency percentiles that climb over time.
  • A spike in connected clients.
  • Slow log entries on large structures.

Testing the online and offline match

To catch training and serving skew, take a sample of entities and compare two things: the feature row computed offline, and the row read from Redis. Differences in types, rounding, missing handling, or freshness show up quickly. Run this check on a schedule and alert when mismatches pass a small threshold.

Common mistakes

  • Using Redis as the only copy of important data without durable persistence.
  • Forgetting TTLs, so memory fills with stale keys.
  • Letting all keys expire at the same moment.
  • Running slow, whole-keyspace commands on a busy server.
  • Storing huge values or huge lists under a single key.
  • Using it as a general database with ad hoc queries.
  • Ignoring type conversion when reading hashes, so numbers become strings in the model input.
  • Filling absent feature fields with zeros and creating training and serving skew.
  • Leaving the server open without authentication.
  • Treating pub-sub as durable messaging, when messages are lost if no one is listening.
  • Skipping memory limits and eviction policy settings.

Frequently asked questions

What is Redis used for?

Redis is used mainly for caching, session storage, counters, rate limiting, leaderboards, and lightweight queues or streams. It is chosen when low latency and high throughput matter more than storing large volumes of history. Many web applications place it in front of a main database.

Is Redis a database or a cache?

It can be either. Out of the box it is often used as a cache, but with persistence, replication, and careful design it can hold primary data for use cases that fit in memory. You should decide which role it plays and configure it for that role.

Why is Redis so fast?

It keeps data in memory, uses compact structures, and runs each command quickly on a single thread, which avoids locking. Clients can also pipeline many commands in one network trip. Together these give very low latency and high throughput.

What happens to data when Redis restarts?

That depends on persistence settings. With snapshots, it reloads the last saved copy, so recent changes may be lost. With an append-only file, it replays the log and loses little or nothing, depending on the flush policy. With no persistence, it starts empty.

How does Redis scale?

You scale reads by adding replicas and scale data size and write throughput by using cluster mode, which splits keys across nodes by hash slot. Both approaches have rules about multi-key operations and consistency, so plan key design accordingly.

Can Redis store tabular data?

It can store rows as hashes, as JSON strings, or as stream entries. It is good for small, hot slices of tables, such as the latest features for an entity. It is not a replacement for an analytical store when you need to scan large tables.

How does Redis relate to tabular foundation models?

It acts as a fast serving and caching layer around them. It can hold the latest feature rows, the labeled context rows used for in-context learning, cached predictions, and cached classification results. The models themselves read tables as rows and columns, which you can read about at /model/research.

Should I use Redis as a feature store?

For online serving of small, fresh feature sets with strict latency needs, it is a common choice. Pair it with an offline store for history and training, and make sure both are computed by the same logic. Without that, models can behave differently in production than in testing.

What is the difference between pub-sub and streams?

Pub-sub delivers a message to whoever is subscribed right now and does not keep it. Streams store messages in a log, allow consumer groups, and let clients replay from a position. Use streams when you cannot afford to lose messages.

Recent versions and modules provide vector storage and similarity search. It can be enough for modest needs. For very large collections or advanced filtering, specialized vector databases may fit better.

Glossary

  • Append-only file: A persistence log of write commands.
  • Cache-aside: A pattern where the app checks the cache first and fills it on a miss.
  • Cache stampede: Many requests rebuilding the same expired value at once.
  • Consumer group: A set of workers sharing the entries of a stream.
  • Eviction: Removal of keys when memory is full.
  • Hash: A Redis type that maps fields to values.
  • Hash slot: One of the fixed buckets used by cluster mode.
  • HyperLogLog: A structure for approximate distinct counts.
  • Pipelining: Sending many commands without waiting for each reply.
  • Pub-sub: Live message broadcast to current subscribers.
  • Replica: A server that copies a primary.
  • Sentinel: A monitor that promotes a replica when the primary fails.
  • Snapshot: A point-in-time copy of data on disk.
  • Sorted set: A set of unique members ordered by score.
  • Stream: An append-only log data type.
  • TTL: Time to live of a key.
  • Training and serving skew: Differences between data seen in training and in production.

Summary

Redis is an in-memory data store with rich structures, optional persistence, replication, and clustering. It delivers very low latency for caching, counters, queues, leaderboards, and streams. Its limits are memory capacity, a lack of general queries, and weaker durability guarantees than a database built for storage.

For tabular foundation models, Redis is the fast lane around the model. It serves the latest feature rows as hashes, holds recent labeled context rows for in-context learning, keeps running statistics that feed continual updates, caches predictions and classification results, and supports quick anomaly checks. The main care points are consistent column order and types, treating absent fields as missing values, matching offline and online feature logic, and setting sensible TTLs. For more on the models, see /model/research, /model/architecture, and /model/benchmarks.

It belongs to Databases and sync in my stack, under Data engineering and lakehouse. Others in the same group:

Type to search.
    ↑↓ navigate↵ open