16.3.1. Introduction to Redis
Table of Contents
Why Redis Matters for Backend Developers
Redis is an in-memory data store that many backend systems use as a powerful helper next to a traditional database. You can think of it as a very fast, shared dictionary that lives in memory and can be accessed by many servers at the same time.
Unlike PostgreSQL or other relational databases, which are focused on long term, structured storage, Redis focuses on speed and simple operations. It is often used for:
- Caching expensive computations or database queries
- Handling sessions for logged-in users
- Implementing rate limiting
- Managing queues and background jobs
- Storing small pieces of data that change very often
If you build any non-trivial backend, you will almost certainly work with Redis at some point.
Key idea: Redis keeps data in memory which makes it extremely fast, but memory is limited and more expensive than disk. Use Redis for data that must be fast, but not necessarily stored forever.
What Redis Actually Is
In-memory key value store
At its core, Redis is a key value store:
- A key is a string that identifies a piece of data, for example
"user:123:name". - A value can be different data structures, such as a string, list, set, or hash.
You connect to Redis, then send commands like:
SET user:1:name "Alice"GET user:1:name
The server responds immediately, usually in microseconds or milliseconds.
Because data lives in memory, Redis can serve thousands or even hundreds of thousands of operations per second on modest hardware.
Single threaded but very fast
Redis uses a single thread to process commands. That sounds like a limitation, but in practice it simplifies concurrency and is still extremely fast, because:
- Memory access is very quick.
- Commands are small and simple.
- There is no complex query planning like in SQL databases.
If you need even more capacity, you run multiple Redis instances or a cluster, instead of trying to use more CPU cores in one instance.
Use cases vs relational databases
You should not think of Redis as a replacement for a relational database, but as a complement.
| Use case | Better fit |
|---|---|
| Financial transactions | Relational DB (Postgres) |
| User profiles and long term data | Relational DB |
| Caching query results | Redis |
| Temporary tokens, sessions | Redis |
| Rate limiting counters | Redis |
| Short-lived queues | Redis |
Redis is great for fast, simple operations on data that you can recompute or rebuild if Redis restarts.
Simple Mental Model
A simple way to imagine Redis:
- You have one giant Python dictionary in memory:
redis = {}
redis["user:1:name"] = "Alice"
redis["user:1:age"] = 30- Multiple web servers can read and write to this dictionary at the same time, through the Redis server.
- Redis provides atomic operations so that common patterns are safe. For example:
redis["page_views"] += 1corresponds to the Redis command:
INCR page_viewsand Redis guarantees that each increment is applied correctly, even with many clients.
Of course Redis is more advanced than a simple dictionary, but this model helps when you start.
Typical Redis Workflow in a Backend
1. Connect from your application
From a Python backend you usually install a client library like redis-py:
pip install redisThen in code:
import redis
r = redis.Redis(host="localhost", port=6379, db=0)
r.set("greeting", "Hello, Redis!")
value = r.get("greeting")
print(value.decode()) # "Hello, Redis!"The Redis server is a separate process, listening on a port, usually 6379.
2. Store and retrieve simple values
Basic operations look like this:
r.set("user:1:name", "Alice")
r.set("user:1:age", 30)
name = r.get("user:1:name") # b'Alice'
age = r.get("user:1:age") # b'30'In many use cases, values are small strings, JSON blobs, or simple counters.
3. Use Redis for caching
A very common pattern is cache, then fall back to database.
Pseudocode:
def get_user_profile(user_id: int):
key = f"user:{user_id}:profile"
cached = r.get(key)
if cached is not None:
return json.loads(cached)
# Not in cache, fetch from database
profile = db.fetch_user_profile(user_id)
# Store in cache for 60 seconds
r.setex(key, 60, json.dumps(profile))
return profileThe idea:
- Try Redis first.
- If not found, go to the database.
- Store the database result in Redis for some time.
This pattern reduces database load and response times.
4. Handling expiration
In caching and other scenarios, you often want data to disappear automatically.
Example:
# Set a key that expires after 10 minutes (600 seconds)
r.setex("reset_token:abc123", 600, "user_id:42")This is useful for:
- Password reset tokens
- Email verification tokens
- Temporary feature flags
- Rate limiting counters
Key Concepts You Will See Later
The following concepts will have their own chapters, but it helps to see where they fit:
- Keys and values are the basic building blocks.
- Data structures like lists, sets, hashes, and sorted sets add powerful operations.
- Expiration lets data disappear automatically after some time.
- Caching uses Redis as a fast layer on top of a slower database.
- Sessions store per user state that must be accessed by multiple app servers.
- Rate limiting uses counters and expiration to restrict how often an action can occur.
- Distributed locks help coordinate tasks across servers without clashes.
This chapter focuses on the big picture of Redis. Implementation details of these features will come later.
Example: Simple Rate Limiting Idea
To illustrate Redis usefulness, here is a simplified rate limiting idea, without going deep:
Goal: allow at most 100 requests per user per minute.
Conceptual steps:
- For each user and each minute, create a key like:
rate:USER_ID:TIMESTAMP_MINUTE - Every time a request is made:
- Increment a counter in Redis.
- Set expiration to 60 seconds.
- If the value is above 100, reject the request.
Pseudocode:
def is_allowed(user_id: int) -> bool:
now_minute = int(time.time() // 60)
key = f"rate:{user_id}:{now_minute}"
# Atomically increment and get the new value
current = r.incr(key)
if current == 1:
# First request in this minute, set expiration
r.expire(key, 60)
return current <= 100This is hard to implement correctly with a traditional database at high load, but Redis makes it straightforward and efficient.
When Not to Use Redis
Redis is not the right tool for:
- Storing large files or large binary data.
- Complex relational queries with joins.
- Data that must never be lost unless you have proper persistence and replication configured.
- Heavy analytics queries that scan large datasets.
Use Redis for fast, simple operations and keep your main business data in a durable database like PostgreSQL.
Summary
- Redis is an in-memory key value store that is very fast and widely used in backend systems.
- It complements relational databases and is ideal for caching, sessions, rate limiting, queues, and other high speed tasks.
- You interact with Redis through simple commands like
SET,GET, andINCR, using client libraries from your backend code. - Because data is in memory and often temporary, you should store only the kind of data you can recompute or that is not critical to keep forever.
Later chapters will show you how to install Redis, work with keys and values, use different data structures, configure expiration, and integrate Redis with FastAPI.
Views: 6
KAHIBARO