Back to blog

Learning Redis: The Complete Beginner's Guide

redisdatabasecachingbackendperformance
Learning Redis: The Complete Beginner's Guide

Introduction

Redis (Remote Dictionary Server) is an open-source, in-memory data structure store that serves as a database, cache, message broker, and streaming engine. It's one of the most popular tools in modern software development, powering everything from session management to real-time analytics.

Before diving into Redis caching with Spring Boot or any other framework integration, understanding Redis fundamentals is essential. This guide will give you a solid foundation.

What You'll Learn:

✅ What Redis is and why it's so fast
✅ Core data structures (Strings, Lists, Sets, Hashes, Sorted Sets)
✅ Essential Redis commands
✅ Persistence options (RDB vs AOF)
✅ Pub/Sub messaging patterns
✅ Real-world use cases
✅ Best practices for production

Prerequisites:

  • Basic command line knowledge
  • Docker installed (for running Redis locally)
  • Understanding of key-value concepts

Why Redis?

Speed That Matters

Redis stores all data in memory, achieving:

  • Sub-millisecond latency for most operations
  • 100,000+ operations per second on modest hardware
  • Millions of ops/sec with proper configuration

Compare this to traditional databases:

OperationPostgreSQLRedis
Simple Read1-10ms0.1-0.5ms
Simple Write5-20ms0.1-0.5ms
Complex Query10-100ms+N/A*

*Redis doesn't support complex queries - it's optimized for simple, fast operations.

More Than Just a Cache

While caching is Redis's most common use case, it's incredibly versatile:

  • Session Store: User sessions with automatic expiration
  • Rate Limiter: Track API requests per user/IP
  • Leaderboards: Sorted sets for real-time rankings
  • Message Queue: Pub/Sub for real-time messaging
  • Real-time Analytics: Counters and HyperLogLog for statistics
  • Geospatial: Location-based queries and radius searches

Getting Started

Installing Redis with Docker

The easiest way to run Redis locally:

# Run Redis container
docker run -d \
  --name redis-local \
  -p 6379:6379 \
  redis:7-alpine
 
# Verify it's running
docker ps | grep redis
 
# Connect to Redis CLI
docker exec -it redis-local redis-cli

You should see the Redis prompt:

127.0.0.1:6379>

Your First Commands

Let's start with basic operations:

# Set a key
SET greeting "Hello, Redis!"
 
# Get a key
GET greeting
# Returns: "Hello, Redis!"
 
# Check if key exists
EXISTS greeting
# Returns: 1 (true)
 
# Delete a key
DEL greeting
 
# Check again
EXISTS greeting
# Returns: 0 (false)

Core Data Structures

Redis isn't just a key-value store - it supports rich data structures that enable powerful operations.

1. Strings

The simplest and most versatile data type. Can store text, numbers, or binary data up to 512MB.

# Basic string operations
SET user:1:name "John Doe"
GET user:1:name
 
# Set with expiration (seconds)
SET session:abc123 "user_data" EX 3600  # Expires in 1 hour
 
# Set only if key doesn't exist (useful for locks)
SETNX lock:resource "locked"
 
# Increment/Decrement (atomic operations)
SET counter 0
INCR counter    # Returns: 1
INCR counter    # Returns: 2
INCRBY counter 10  # Returns: 12
DECR counter    # Returns: 11
 
# Multiple operations
MSET user:1:name "John" user:1:email "john@example.com"
MGET user:1:name user:1:email

Use Cases:

  • Caching serialized objects
  • Counters and statistics
  • Rate limiting
  • Distributed locks

2. Lists

Ordered collections of strings. Perfect for queues and recent items.

# Add items to list
LPUSH notifications "New message"    # Add to left (head)
RPUSH notifications "Friend request" # Add to right (tail)
 
# Get list length
LLEN notifications
 
# Get items by range (0-indexed, -1 means last)
LRANGE notifications 0 -1  # Get all items
LRANGE notifications 0 4   # Get first 5 items
 
# Pop items (remove and return)
LPOP notifications  # Remove from left
RPOP notifications  # Remove from right
 
# Blocking pop (wait for items)
BLPOP queue:jobs 30  # Wait up to 30 seconds for item

Use Cases:

  • Message queues (producer/consumer pattern)
  • Recent activity feeds
  • Undo/redo stacks
  • Task queues

3. Sets

Unordered collections of unique strings. Great for membership testing and set operations.

# Add members to set
SADD tags:post:1 "redis" "database" "caching"
 
# Check membership
SISMEMBER tags:post:1 "redis"  # Returns: 1 (true)
SISMEMBER tags:post:1 "python" # Returns: 0 (false)
 
# Get all members
SMEMBERS tags:post:1
 
# Set operations
SADD tags:post:2 "redis" "spring" "java"
 
SINTER tags:post:1 tags:post:2   # Intersection: ["redis"]
SUNION tags:post:1 tags:post:2   # Union: all unique tags
SDIFF tags:post:1 tags:post:2    # Difference: tags in post:1 but not post:2
 
# Random member
SRANDMEMBER tags:post:1
 
# Count members
SCARD tags:post:1

Use Cases:

  • Tags and categories
  • Unique visitors tracking
  • Friend lists and social connections
  • Voting systems (prevent duplicate votes)

4. Hashes

Maps between string fields and values. Perfect for objects.

# Set hash fields
HSET user:1 name "John Doe" email "john@example.com" age 30
 
# Get single field
HGET user:1 name
 
# Get multiple fields
HMGET user:1 name email
 
# Get all fields and values
HGETALL user:1
 
# Increment numeric field
HINCRBY user:1 age 1  # Now 31
 
# Check field existence
HEXISTS user:1 email
 
# Get all field names
HKEYS user:1
 
# Delete field
HDEL user:1 age

Use Cases:

  • User profiles and sessions
  • Product details
  • Configuration settings
  • Object caching (more memory efficient than JSON strings)

5. Sorted Sets

Like sets, but each member has a score for ordering. Incredibly powerful for rankings.

# Add members with scores
ZADD leaderboard 100 "player:1" 85 "player:2" 92 "player:3"
 
# Get rank (0-indexed, lowest score first)
ZRANK leaderboard "player:1"      # Returns position
 
# Get reverse rank (highest score first)
ZREVRANK leaderboard "player:1"
 
# Get score
ZSCORE leaderboard "player:1"
 
# Get range by rank (with scores)
ZRANGE leaderboard 0 2 WITHSCORES        # Top 3 (ascending)
ZREVRANGE leaderboard 0 2 WITHSCORES     # Top 3 (descending)
 
# Get range by score
ZRANGEBYSCORE leaderboard 80 95 WITHSCORES
 
# Increment score
ZINCRBY leaderboard 10 "player:2"  # player:2 now has 95
 
# Count members in score range
ZCOUNT leaderboard 80 100
 
# Remove members
ZREM leaderboard "player:3"

Use Cases:

  • Leaderboards and rankings
  • Priority queues
  • Time-based data (use timestamp as score)
  • Rate limiting with sliding windows

Key Expiration and TTL

Redis can automatically expire keys after a specified time - essential for caching.

# Set key with expiration
SET session:token "user_data" EX 3600    # Expires in 3600 seconds
SET session:token "user_data" PX 60000   # Expires in 60000 milliseconds
 
# Set expiration on existing key
EXPIRE session:token 1800        # 30 minutes from now
EXPIREAT session:token 1735689600  # Unix timestamp
 
# Check remaining TTL
TTL session:token    # Returns seconds, -1 if no expiry, -2 if key doesn't exist
PTTL session:token   # Returns milliseconds
 
# Remove expiration (make persistent)
PERSIST session:token

Best Practices:

  • Always set TTL on cache entries
  • Use appropriate TTL based on data volatility
  • Consider memory limits when setting long TTLs
  • Use SCAN instead of KEYS * in production (non-blocking)

Persistence Options

Redis stores data in memory, but offers persistence for durability.

RDB (Redis Database)

Point-in-time snapshots saved to disk.

# Manual snapshot
BGSAVE  # Background save
 
# Configuration (redis.conf)
# save 900 1      # Save if 1 key changed in 900 seconds
# save 300 10     # Save if 10 keys changed in 300 seconds
# save 60 10000   # Save if 10000 keys changed in 60 seconds

Pros:

  • Compact single file
  • Fast restarts
  • Good for backups

Cons:

  • Data loss possible (up to last snapshot)
  • Fork can be slow with large datasets

AOF (Append-Only File)

Logs every write operation.

# Configuration (redis.conf)
# appendonly yes
# appendfsync everysec  # Sync every second (recommended)
# appendfsync always    # Sync on every write (slower but safer)
# appendfsync no        # Let OS decide (fastest but risky)

Pros:

  • More durable (minimal data loss)
  • Human-readable log
  • Auto-rewrite to compact size

Cons:

  • Larger files than RDB
  • Slower restarts

Use both RDB and AOF:

# redis.conf
appendonly yes
appendfsync everysec
save 900 1
save 300 10

Pub/Sub Messaging

Redis supports publish/subscribe messaging for real-time communication.

# Terminal 1: Subscribe to channel
SUBSCRIBE news:tech
 
# Terminal 2: Publish message
PUBLISH news:tech "Redis 7.2 released!"
 
# Pattern subscription
PSUBSCRIBE news:*  # Subscribe to all news channels
 
# Unsubscribe
UNSUBSCRIBE news:tech

Use Cases:

  • Real-time notifications
  • Chat applications
  • Live updates (sports scores, stock prices)
  • Cache invalidation across servers

Limitations:

  • No message persistence (missed if subscriber offline)
  • No acknowledgment mechanism
  • Consider Redis Streams for more robust messaging

Transactions

Redis supports atomic transactions with MULTI/EXEC.

# Start transaction
MULTI
 
# Queue commands
SET user:1:balance 100
DECRBY user:1:balance 25
INCRBY user:2:balance 25
 
# Execute all commands atomically
EXEC
 
# Cancel transaction
DISCARD

Watch for Optimistic Locking:

WATCH user:1:balance
val = GET user:1:balance
MULTI
SET user:1:balance (val - 25)
EXEC  # Fails if user:1:balance changed since WATCH

Lua Scripting

For complex atomic operations, use Lua scripts.

# Simple script
EVAL "return redis.call('GET', KEYS[1])" 1 mykey
 
# Transfer funds atomically
EVAL "
local from = KEYS[1]
local to = KEYS[2]
local amount = tonumber(ARGV[1])
 
local balance = tonumber(redis.call('GET', from))
if balance >= amount then
    redis.call('DECRBY', from, amount)
    redis.call('INCRBY', to, amount)
    return 1
end
return 0
" 2 user:1:balance user:2:balance 50

Benefits:

  • Atomic execution
  • Reduced network round trips
  • Complex logic in single call

Real-World Use Cases

1. Session Management

# Store session
HSET session:abc123 user_id 1 username "john" role "admin"
EXPIRE session:abc123 3600
 
# Validate session
EXISTS session:abc123
HGET session:abc123 user_id
 
# Extend session
EXPIRE session:abc123 3600
 
# Logout
DEL session:abc123

2. Rate Limiting

# Simple rate limiter (10 requests per minute)
local key = "ratelimit:" .. user_id
local count = redis.call('INCR', key)
if count == 1 then
    redis.call('EXPIRE', key, 60)
end
if count > 10 then
    return 0  -- Rate limited
end
return 1  -- Allowed

3. Caching with Cache-Aside Pattern

# Check cache first
cached = GET cache:user:1
 
if cached is nil then
    # Cache miss - fetch from database
    data = fetch_from_database(1)
 
    # Store in cache with TTL
    SET cache:user:1 data EX 300
 
    return data
else
    return cached
end

4. Real-Time Leaderboard

# Update score on action
ZINCRBY game:leaderboard 10 "player:123"
 
# Get top 10 players
ZREVRANGE game:leaderboard 0 9 WITHSCORES
 
# Get player rank
ZREVRANK game:leaderboard "player:123"

5. Job Queue

# Producer: Add job
LPUSH jobs:pending '{"type":"email","to":"user@example.com"}'
 
# Consumer: Process job (blocking)
job = BRPOP jobs:pending 30
# Process job...
 
# On failure, push to retry queue
LPUSH jobs:retry job

Production Best Practices

1. Memory Management

# Check memory usage
INFO memory
 
# Set max memory limit
CONFIG SET maxmemory 2gb
 
# Set eviction policy
CONFIG SET maxmemory-policy allkeys-lru

Eviction Policies:

  • noeviction: Return error when memory limit reached
  • allkeys-lru: Evict least recently used keys
  • volatile-lru: Evict LRU keys with TTL set
  • allkeys-random: Random eviction
  • volatile-ttl: Evict keys with shortest TTL

2. Key Naming Conventions

Use colons to create namespaces:

user:1:profile
user:1:sessions
cache:products:123
queue:emails:pending

3. Avoid Anti-Patterns

# ❌ Never use KEYS in production (blocks server)
KEYS user:*
 
# ✅ Use SCAN instead (cursor-based, non-blocking)
SCAN 0 MATCH user:* COUNT 100

4. Connection Pooling

Always use connection pools in your application:

// Spring Boot example
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(128);
poolConfig.setMaxIdle(64);
poolConfig.setMinIdle(16);

5. Monitoring

Essential metrics to monitor:

  • Memory usage (used_memory)
  • Connected clients
  • Commands per second
  • Cache hit rate
  • Keyspace statistics

Summary

Redis is a powerful, versatile tool that every backend developer should know:

Key Takeaways:

✅ Redis is an in-memory data structure store with sub-millisecond latency
✅ Five core data types: Strings, Lists, Sets, Hashes, Sorted Sets
✅ Use TTL for automatic key expiration
✅ Choose persistence based on durability needs (RDB vs AOF)
✅ Pub/Sub enables real-time messaging
✅ Lua scripts for atomic complex operations
✅ Follow best practices for production deployments

Next Steps:

  1. Practice: Run Redis locally and experiment with commands
  2. Build: Create a simple rate limiter or session store
  3. Integrate: Add Redis caching to your application
  4. Learn More: Explore Redis Streams, Cluster, and Sentinel

Additional Resources

Official Documentation:

Related Tutorials:

Tools:


Ready to implement Redis in your applications? Check out Spring Boot Caching with Redis for a complete integration guide!

📬 Subscribe to Newsletter

Get the latest blog posts delivered to your inbox every week. No spam, unsubscribe anytime.

We respect your privacy. Unsubscribe at any time.

💬 Comments

Sign in to leave a comment

We'll never post without your permission.