Skip to content
Redis Explained — Caching & Data Structures for Beginners

Redis Explained — Caching & Data Structures for Beginners

DodaTech Updated Jun 6, 2026 11 min read

Redis is an in-memory data structure store used as a database, cache, and message broker, known for its blazing-fast performance and versatile data types like strings, hashes, lists, and sets.

What You’ll Learn

By the end of this tutorial, you’ll understand Redis data structures (strings, hashes, lists, sets, sorted sets), implement caching patterns, use pub/sub messaging, and know where Redis fits in modern application architecture.

Why Redis Matters

Redis is the most popular caching and session store in the world, used by Twitter, GitHub, Stack Overflow, and thousands of other companies. At DodaTech, Redis powers Doda Browser’s session cache and Durga Antivirus Pro’s real-time threat lookup. A single Redis instance can handle millions of operations per second.

Redis Learning Path

    flowchart LR
  A[SQL Basics] --> B[MySQL]
  B --> C[PostgreSQL]
  C --> D[MongoDB]
  D --> E[Redis]
  E --> F[Database Design]
  E --> G{You Are Here}
  style G fill:#f90,color:#fff
  
Prerequisites: Basic database concepts. SQL or MongoDB experience helps for comparison. Understanding of key-value storage is useful.

What Is Redis? (The “Why” First)

Think of Redis as a supercharged sticky note board right next to your computer. When you need a piece of information quickly — a user’s session, a product detail, the latest notifications — instead of walking to the filing cabinet (your database), you check your sticky notes (Redis). It’s incredibly fast because everything is kept in RAM.

Redis vs Traditional Databases

AspectRedisMySQL/PostgreSQLMongoDB
StorageIn-memory (RAM)DiskDisk + memory
SpeedMicrosecondsMillisecondsMilliseconds
Data modelKey-value + structuresRelational tablesDocuments
PersistenceOptional (RDB/AOF)AlwaysAlways
Use caseCache, real-timePrimary storagePrimary storage

Installing Redis

# Ubuntu/Debian
sudo apt update
sudo apt install redis-server -y
sudo systemctl start redis

# macOS
brew install redis
brew services start redis

# Verify
redis-cli ping
# Output: PONG

Redis Data Structures

Redis is more than a simple key-value store. It provides specialized data structures for different use cases.

1. Strings — The Foundation

Strings are the most basic Redis type — key-value pairs where the value is text, numbers, or binary data:

# Set and get a string
SET user:1:name "Alice Johnson"
GET user:1:name
# Output: "Alice Johnson"

# Strings also support numeric operations
SET counter 100
INCR counter      # 101
INCRBY counter 5  # 106
DECR counter      # 105
GET counter
# Output: "105"

# Set with expiration (TTL)
SET session:abc123 "user_data" EX 3600  # Expires in 1 hour
TTL session:abc123
# Output: 3599 (seconds remaining)

Use cases: Caching HTML fragments, storing session data, rate limiting counters.

2. Hashes — Object Storage

Hashes are like miniature JSON objects — they store multiple fields under one key:

# Store user data as a hash
HSET user:1 name "Alice Johnson" email "alice@example.com" age 28 city "New York"

# Get specific fields
HGET user:1 name
# Output: "Alice Johnson"

# Get all fields
HGETALL user:1
# Output:
# 1) "name"
# 2) "Alice Johnson"
# 3) "email"
# 4) "alice@example.com"
# 5) "age"
# 6) "28"

# Increment a field
HINCRBY user:1 age 1
# Output: 29

# Check if field exists
HEXISTS user:1 email
# Output: (integer) 1

Use cases: User profiles, product details, any object-like data that’s accessed by key.

3. Lists — Ordered Sequences

Lists are ordered sequences of strings, optimized for push/pop operations at both ends:

# Add to the right (end)
RPUSH notifications:user1 "New message from Bob"
RPUSH notifications:user1 "Your order has shipped"
RPUSH notifications:user1 "Password changed"

# Add to the left (beginning)
LPUSH notifications:user1 "URGENT: Account alert!"

# Get range (0 = first, -1 = last)
LRANGE notifications:user1 0 -1
# Output:
# 1) "URGENT: Account alert!"
# 2) "New message from Bob"
# 3) "Your order has shipped"
# 4) "Password changed"

# Pop from left (dequeue)
LPOP notifications:user1
# Output: "URGENT: Account alert!"

# Trim to specific length
LTRIM notifications:user1 0 49  # Keep only the 50 most recent

Use cases: Message queues, activity feeds, chat message history.

4. Sets — Unique Collections

Sets store unique, unordered members with O(1) membership check:

# Add members
SADD tags:post:1 "redis" "database" "nosql" "caching"
SADD tags:post:1 "redis" "tutorial"  # "redis" already exists, ignored

# Get all members
SMEMBERS tags:post:1
# Output: 1) "redis" 2) "database" 3) "nosql" 4) "caching" 5) "tutorial"

# Check membership
SISMEMBER tags:post:1 "redis"
# Output: (integer) 1
SISMEMBER tags:post:1 "mysql"
# Output: (integer) 0

# Set operations — find common tags between posts
SADD tags:post:2 "redis" "nosql" "python"
SINTER tags:post:1 tags:post:2
# Output: 1) "nosql" 2) "redis"

# Union — all tags from both posts
SUNION tags:post:1 tags:post:2

Use cases: Unique visitor tracking, tags, friend relationships, access control lists.

5. Sorted Sets — Ranked Collections

Sorted sets are like sets but every member has a score, and they’re ordered by score:

# Add members with scores (leaderboard)
ZADD leaderboard 100 "Alice"
ZADD leaderboard 85 "Bob"
ZADD leaderboard 95 "Charlie"
ZADD leaderboard 120 "Diana"

# Get top 3 (highest scores)
ZREVRANGE leaderboard 0 2 WITHSCORES
# Output:
# 1) "Diana"
# 2) "120"
# 3) "Alice"
# 4) "100"
# 5) "Charlie"
# 6) "95"

# Get rank of a member
ZRANK leaderboard "Bob"
# Output: 0 (0-indexed from lowest) — Bob is lowest

# Increment score (when someone earns more points)
ZINCRBY leaderboard 15 "Bob"
# Output: "100"

# Get scores within a range
ZRANGEBYSCORE leaderboard 90 110 WITHSCORES

Use cases: Leaderboards, rate limiting (sorted by timestamp), priority queues.

Caching Patterns — Redis’s Killer Feature

Simple Cache-Aside Pattern

This is the most common caching pattern:

import redis
import json

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

def get_product(product_id):
    cache_key = f"product:{product_id}"

    # 1. Try cache first
    cached = cache.get(cache_key)
    if cached is not None:
        print("CACHE HIT")
        return json.loads(cached)

    # 2. Cache miss — get from database
    print("CACHE MISS — fetching from database")
    product = query_database(product_id)  # Your database function

    # 3. Store in cache with TTL
    cache.setex(cache_key, 3600, json.dumps(product))
    return product

def query_database(product_id):
    # Simulate a slow database query
    import time
    time.sleep(2)  # 2 second query time
    return {"id": product_id, "name": "Wireless Mouse", "price": 29.99}

# Test
product = get_product(1)   # Cache miss (2 seconds)
product = get_product(1)   # Cache hit (instant!)
product = get_product(1)   # Cache hit (instant!)

Expected output:

CACHE MISS — fetching from database
CACHE HIT
CACHE HIT

Rate Limiting with Redis

import redis
import time

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

def is_rate_limited(user_id, max_requests=10, window_seconds=60):
    key = f"ratelimit:{user_id}:{int(time.time() / window_seconds)}"
    current = cache.incr(key)

    # Set expiry on first request
    if current == 1:
        cache.expire(key, window_seconds + 1)

    return current > max_requests

# Simulate requests
for i in range(12):
    user = "user_123"
    if is_rate_limited(user):
        print(f"Request {i+1}: RATE LIMITED")
    else:
        print(f"Request {i+1}: Allowed")
    time.sleep(0.1)

Expected output:

Request 1: Allowed
...
Request 10: Allowed
Request 11: RATE LIMITED
Request 12: RATE LIMITED

Session Storage

import redis
import json
import uuid

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

def create_session(user_data):
    session_id = str(uuid.uuid4())
    cache.hset(f"session:{session_id}", mapping=user_data)
    cache.expire(f"session:{session_id}", 86400)  # 24 hours
    return session_id

def get_session(session_id):
    data = cache.hgetall(f"session:{session_id}")
    return data if data else None

# Usage
session = create_session({
    "user_id": "123",
    "username": "alice",
    "role": "admin"
})

print(f"Session ID: {session}")
print(f"Session data: {get_session(session)}")

Pub/Sub — Real-Time Messaging

Redis supports publish/subscribe messaging — one-to-many message broadcasting:

# publisher.py
import redis

r = redis.Redis(host="localhost", port=6379, decode_responses=True)
r.publish("notifications", json.dumps({
    "type": "order_shipped",
    "order_id": 1234,
    "user_id": 567
}))
print("Message published!")
# subscriber.py
import redis

r = redis.Redis(host="localhost", port=6379, decode_responses=True)
pubsub = r.pubsub()
pubsub.subscribe("notifications")

print("Waiting for messages...")
for message in pubsub.listen():
    if message["type"] == "message":
        print(f"Received: {message['data']}")

Use cases: Real-time notifications, live chat, event broadcasting, cache invalidation across servers.

Persistence — Does Redis Lose Data on Restart?

Redis can persist data to disk. Two options:

MethodHow It WorksRecovery SpeedData Loss
RDB (snapshot)Periodic snapshotsFast (single file)Last snapshot interval
AOF (append-only)Logs every writeSlower (replay)Last second (with always fsync)
RDB + AOFBothAOF used firstBest protection
# Configure in redis.conf
save 900 1      # RDB: save if 1 key changed in 900 seconds
save 300 10     # RDB: save if 10 keys changed in 300 seconds
appendonly yes  # Enable AOF
appendfsync everysec  # AOF: fsync every second (good balance)

Common Redis Mistakes

1. Using Redis as a Primary Database

Redis is an in-memory store. While it can persist data, it’s designed as a cache/session store. If you lose your Redis server, you should be able to rebuild data from your primary database.

2. Not Setting Expiry (TTL)

Keys without TTL accumulate forever. For caches and sessions, always set TTL. Monitor memory usage and use MAXMEMORY policy to evict old data.

3. Storing Large Values

Redis works best with values under 100KB. Large values (MB+) consume memory and slow down operations. Store large objects in object storage (S3) and keep URLs in Redis.

4. Using KEYS in Production

KEYS * blocks Redis for the duration of the scan — unacceptable in production. Use SCAN for production iteration:

# NEVER do this in production:
KEYS user:*

# Use SCAN instead:
SCAN 0 MATCH user:* COUNT 100

5. Ignoring Connection Pooling

Creating a new Redis connection for every request is expensive. Use connection pooling (most Redis clients support this automatically, but verify).

6. Forgetting About Memory Limits

Redis stores everything in RAM. Set maxmemory in redis.conf and choose an eviction policy:

maxmemory 4gb
maxmemory-policy allkeys-lru  # Evict least recently used keys

7. Not Using Redis for What It’s Good At

Don’t force relational patterns into Redis. Redis is not for complex queries, joins, or report generation. Use it for specific high-performance use cases.

Common Mistakes Beginners Make

1. Skipping the Fundamentals

Many beginners jump straight to advanced topics without mastering the basics. Take time to understand the core concepts before moving on.

2. Not Practicing Enough

Reading tutorials without writing code leads to shallow understanding. Code along with every example and experiment on your own.

3. Ignoring Error Messages

Error messages tell you exactly what went wrong. Read them carefully — they usually point to the line and type of issue.

4. Copy-Pasting Without Understanding

It’s tempting to copy code from tutorials, but typing it yourself and understanding each line builds real skill.

5. Giving Up Too Early

Every developer hits frustrating bugs. Take breaks, ask for help, and remember that struggling is part of learning.

Practice Questions

1. What data structures does Redis support?

Strings, hashes, lists, sets, sorted sets, bitmaps, hyperloglogs, geospatial indexes, and streams.

2. What does SET key value EX 3600 do?

Sets a key with a value and a TTL of 3600 seconds (1 hour). After 3600 seconds, the key is automatically deleted.

3. How does caching improve application performance?

By storing frequently accessed data in fast RAM (Redis), avoiding slow database queries. A cache hit returns data in microseconds vs milliseconds from the database.

4. What’s the difference between a list and a set in Redis?

Lists are ordered (can have duplicates, supports index access). Sets are unordered (no duplicates, supports membership check and set operations like union/intersection).

5. Challenge: Implement a simple task queue using Redis lists.

# Producer: add tasks
LPUSH task_queue "process_image:123.jpg"
LPUSH task_queue "send_email:user@example.com"
LPUSH task_queue "generate_report:Q2-2026"

# Consumer: pop and process
RPOP task_queue
# Output: "process_image:123.jpg"

Real-World Task: Build a Rate Limiter

Create a Redis-based rate limiter that prevents API abuse:

import redis
import time
import os

cache = redis.Redis(
    host=os.getenv("REDIS_HOST", "localhost"),
    port=6379,
    decode_responses=True
)

class RateLimiter:
    def __init__(self, max_requests=100, window_seconds=60):
        self.max_requests = max_requests
        self.window = window_seconds

    def check(self, client_id):
        key = f"ratelimit:{client_id}:{int(time.time() / self.window)}"
        count = cache.incr(key)
        if count == 1:
            cache.expire(key, self.window + 1)
        return count <= self.max_requests, self.max_requests - count

# Usage
limiter = RateLimiter(max_requests=5, window_seconds=60)
for i in range(7):
    allowed, remaining = limiter.check("api_client_1")
    status = "✓" if allowed else "✗"
    print(f"[{status}] Request {i+1}: remaining={remaining}")
    time.sleep(0.5)

Expected output:

[✓] Request 1: remaining=4
[✓] Request 2: remaining=3
[✓] Request 3: remaining=2
[✓] Request 4: remaining=1
[✓] Request 5: remaining=0
[✗] Request 6: remaining=0
[✗] Request 7: remaining=0

This exact pattern is used by Doda Browser’s API and Durga Antivirus Pro’s update service to prevent abuse while ensuring legitimate users have full access.

FAQ

Is Redis free to use?
Yes, Redis is open source (BSD license). Redis Stack (which includes RedisJSON, RedisSearch, RedisTimeSeries, and RedisBloom) is also free. Redis Enterprise is the commercial version with advanced clustering and support.
What’s the difference between Redis and Memcached?
Both are in-memory caches, but Redis offers data structures (lists, sets, sorted sets), persistence, pub/sub, and replication. Memcached is simpler (strings only) and multi-threaded. Redis is generally preferred for modern applications.
Can Redis handle millions of operations per second?
Yes. A single Redis instance can handle 100,000+ operations per second. Redis Cluster can scale to millions. Twitter uses Redis to handle over 1 billion operations per day.
How do I connect Redis to my application?
Each programming language has a Redis client library: redis-py (Python), node-redis (Node.js), ioredis (JavaScript), Redisson (Java), go-redis (Go). Connection is via TCP (default port 6379).
What is Redis Cluster?
Redis Cluster automatically shards data across multiple Redis nodes, providing horizontal scalability and high availability. Data is split into 16,384 hash slots distributed across nodes.

Try It Yourself

Install Redis and experiment with all data structures:

# Start Redis CLI
redis-cli

# Play with strings
SET greeting "Hello Redis"
GET greeting

# Play with lists
RPUSH fruits "apple" "banana" "cherry"
LRANGE fruits 0 -1

# Play with sets
SADD developers "alice" "bob" "charlie"
SADD managers "bob" "diana"
SINTER developers managers  # Who is both? "bob"

# Play with sorted sets
ZADD scores 90 "alice" 85 "bob" 95 "charlie"
ZREVRANGE scores 0 -1 WITHSCORES

What’s Next

What’s Next

Congratulations on completing this Redis tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro