Chapter 1: Redis Basics - Complete In-Memory Database Guide
Authored by syscook.dev
What is Redis?
Redis (Remote Dictionary Server) is an open-source, in-memory data structure store that can be used as a database, cache, message broker, and streaming engine. This comprehensive guide will teach you everything you need to know about Redis and how to use it effectively in your applications.
Why Learn Redis?
Redis is essential for modern application development because it:
- High Performance: In-memory storage provides sub-millisecond response times
- Versatile Data Types: Strings, hashes, lists, sets, sorted sets, and more
- Caching: Perfect for application caching and session storage
- Real-time Features: Pub/Sub messaging and streaming capabilities
- Scalability: Master-slave replication and clustering support
- Industry Standard: Used by Twitter, GitHub, Stack Overflow, and many others
Redis (Remote Dictionary Server) is an open-source, in-memory data structure store that can be used as a database, cache, message broker, and streaming engine. It supports various data structures such as strings, hashes, lists, sets, sorted sets, bitmaps, hyperloglogs, and geospatial indexes.
Key Features:
- In-Memory Storage: Data stored in RAM for ultra-fast access
- Data Persistence: Optional persistence to disk
- Data Structures: Rich set of data types
- Atomic Operations: All operations are atomic
- Replication: Master-slave replication
- Clustering: Horizontal scaling with Redis Cluster
- Pub/Sub: Publish/Subscribe messaging
- Lua Scripting: Server-side scripting support
Why Use Redis?
1. Ultra-Fast Performance
Redis stores data in memory, providing microsecond latency for read and write operations.
# Example: Basic Redis operations
redis-cli
# Set a key-value pair
127.0.0.1:6379> SET user:1001 "John Doe"
OK
# Get the value
127.0.0.1:6379> GET user:1001
"John Doe"
# Set with expiration (TTL)
127.0.0.1:6379> SETEX session:abc123 3600 "user_data"
OK
# Check TTL
127.0.0.1:6379> TTL session:abc123
(integer) 3598
Performance Benefits:
- Sub-millisecond response times
- High throughput (hundreds of thousands of operations per second)
- Low latency for real-time applications
- Efficient memory usage
2. Rich Data Structures
Redis supports multiple data types for different use cases.
# String operations
127.0.0.1:6379> SET counter 0
OK
127.0.0.1:6379> INCR counter
(integer) 1
127.0.0.1:6379> INCRBY counter 5
(integer) 6
# Hash operations
127.0.0.1:6379> HSET user:1001 name "John Doe" email "[email protected]" age 30
(integer) 3
127.0.0.1:6379> HGET user:1001 name
"John Doe"
127.0.0.1:6379> HGETALL user:1001
1) "name"
2) "John Doe"
3) "email"
4) "[email protected]"
5) "age"
6) "30"
# List operations
127.0.0.1:6379> LPUSH tasks "task1" "task2" "task3"
(integer) 3
127.0.0.1:6379> LRANGE tasks 0 -1
1) "task3"
2) "task2"
3) "task1"
127.0.0.1:6379> RPOP tasks
"task1"
# Set operations
127.0.0.1:6379> SADD tags "redis" "database" "cache" "nosql"
(integer) 4
127.0.0.1:6379> SMEMBERS tags
1) "nosql"
2) "cache"
3) "database"
4) "redis"
127.0.0.1:6379> SISMEMBER tags "redis"
(integer) 1
# Sorted Set operations
127.0.0.1:6379> ZADD leaderboard 100 "player1" 200 "player2" 150 "player3"
(integer) 3
127.0.0.1:6379> ZRANGE leaderboard 0 -1 WITHSCORES
1) "player1"
2) "100"
3) "player3"
4) "150"
5) "player2"
6) "200"
3. Caching and Session Storage
Redis is widely used for caching and session management.
# Cache example
127.0.0.1:6379> SETEX cache:user:1001:profile 300 '{"name":"John","email":"[email protected]"}'
OK
127.0.0.1:6379> GET cache:user:1001:profile
"{\"name\":\"John\",\"email\":\"[email protected]\"}"
# Session storage
127.0.0.1:6379> HSET session:abc123 user_id 1001 login_time "2024-01-15T10:30:00Z" last_activity "2024-01-15T10:35:00Z"
(integer) 3
127.0.0.1:6379> EXPIRE session:abc123 1800
(integer) 1
How Does Redis Work?
1. Memory Architecture
Data Storage
Redis stores all data in memory for maximum performance:
# Check memory usage
127.0.0.1:6379> INFO memory
# Memory
used_memory:1048576
used_memory_human:1.00M
used_memory_rss:2097152
used_memory_rss_human:2.00M
used_memory_peak:1048576
used_memory_peak_human:1.00M
used_memory_peak_perc:100.00%
used_memory_overhead:1038336
used_memory_startup:980736
used_memory_dataset:10240
used_memory_dataset_perc:1.00%
Persistence Options
Redis offers different persistence mechanisms:
# RDB (Redis Database Backup)
# Automatic snapshots at specified intervals
# Configuration in redis.conf:
# save 900 1 # Save if at least 1 key changed in 900 seconds
# save 300 10 # Save if at least 10 keys changed in 300 seconds
# save 60 10000 # Save if at least 10000 keys changed in 60 seconds
# AOF (Append Only File)
# Logs every write operation
# Configuration in redis.conf:
# appendonly yes
# appendfsync everysec # Sync every second
2. Data Types and Operations
Strings
The most basic Redis data type:
# Basic string operations
127.0.0.1:6379> SET mykey "Hello World"
OK
127.0.0.1:6379> GET mykey
"Hello World"
127.0.0.1:6379> STRLEN mykey
(integer) 11
127.0.0.1:6379> APPEND mykey " Redis"
(integer) 17
127.0.0.1:6379> GET mykey
"Hello World Redis"
# Numeric operations
127.0.0.1:6379> SET counter 0
OK
127.0.0.1:6379> INCR counter
(integer) 1
127.0.0.1:6379> INCRBY counter 10
(integer) 11
127.0.0.1:6379> DECR counter
(integer) 10
127.0.0.1:6379> DECRBY counter 5
(integer) 5
# Bit operations
127.0.0.1:6379> SETBIT mykey 7 1
(integer) 0
127.0.0.1:6379> GETBIT mykey 7
(integer) 1
127.0.0.1:6379> BITCOUNT mykey
(integer) 1
Hashes
Perfect for storing objects:
# Hash operations
127.0.0.1:6379> HSET user:1001 name "John Doe" email "[email protected]" age 30
(integer) 3
127.0.0.1:6379> HGET user:1001 name
"John Doe"
127.0.0.1:6379> HGETALL user:1001
1) "name"
2) "John Doe"
3) "email"
4) "[email protected]"
5) "age"
6) "30"
127.0.0.1:6379> HKEYS user:1001
1) "name"
2) "email"
3) "age"
127.0.0.1:6379> HVALS user:1001
1) "John Doe"
2) "[email protected]"
3) "30"
127.0.0.1:6379> HEXISTS user:1001 name
(integer) 1
127.0.0.1:6379> HDEL user:1001 age
(integer) 1
Lists
Ordered collections of strings:
# List operations
127.0.0.1:6379> LPUSH tasks "task1" "task2" "task3"
(integer) 3
127.0.0.1:6379> LRANGE tasks 0 -1
1) "task3"
2) "task2"
3) "task1"
127.0.0.1:6379> RPUSH tasks "task4"
(integer) 4
127.0.0.1:6379> LPOP tasks
"task3"
127.0.0.1:6379> RPOP tasks
"task4"
127.0.0.1:6379> LLEN tasks
(integer) 2
127.0.0.1:6379> LINDEX tasks 0
"task2"
127.0.0.1:6379> LINSERT tasks BEFORE "task2" "newtask"
(integer) 3
Sets
Unordered collections of unique strings:
# Set operations
127.0.0.1:6379> SADD tags "redis" "database" "cache" "nosql"
(integer) 4
127.0.0.1:6379> SMEMBERS tags
1) "nosql"
2) "cache"
3) "database"
4) "redis"
127.0.0.1:6379> SISMEMBER tags "redis"
(integer) 1
127.0.0.1:6379> SCARD tags
(integer) 4
127.0.0.1:6379> SADD tags2 "redis" "python" "web"
(integer) 3
127.0.0.1:6379> SINTER tags tags2
1) "redis"
127.0.0.1:6379> SUNION tags tags2
1) "nosql"
2) "cache"
3) "database"
4) "redis"
5) "python"
6) "web"
127.0.0.1:6379> SDIFF tags tags2
1) "nosql"
2) "cache"
3) "database"
Sorted Sets
Sets with scores for ordering:
# Sorted Set operations
127.0.0.1:6379> ZADD leaderboard 100 "player1" 200 "player2" 150 "player3"
(integer) 3
127.0.0.1:6379> ZRANGE leaderboard 0 -1 WITHSCORES
1) "player1"
2) "100"
3) "player3"
4) "150"
5) "player2"
6) "200"
127.0.0.1:6379> ZRANK leaderboard "player2"
(integer) 2
127.0.0.1:6379> ZSCORE leaderboard "player1"
"100"
127.0.0.1:6379> ZCOUNT leaderboard 100 200
(integer) 3
127.0.0.1:6379> ZINCRBY leaderboard 50 "player1"
"150"
3. Key Management
Key Operations
# Key operations
127.0.0.1:6379> SET mykey "value"
OK
127.0.0.1:6379> EXISTS mykey
(integer) 1
127.0.0.1:6379> TYPE mykey
string
127.0.0.1:6379> EXPIRE mykey 60
(integer) 1
127.0.0.1:6379> TTL mykey
(integer) 58
127.0.0.1:6379> PERSIST mykey
(integer) 1
127.0.0.1:6379> TTL mykey
(integer) -1
127.0.0.1:6379> DEL mykey
(integer) 1
127.0.0.1:6379> EXISTS mykey
(integer) 0
# Pattern matching
127.0.0.1:6379> SET user:1:name "John"
OK
127.0.0.1:6379> SET user:2:name "Jane"
OK
127.0.0.1:6379> SET user:3:name "Bob"
OK
127.0.0.1:6379> KEYS user:*
1) "user:2:name"
2) "user:1:name"
3) "user:3:name"
127.0.0.1:6379> SCAN 0 MATCH user:* COUNT 10
1) "0"
2) 1) "user:2:name"
2) "user:1:name"
3) "user:3:name"
Practical Examples
1. Simple Caching System
Basic Cache Implementation
#!/bin/bash
# cache-example.sh
# Set cache with TTL
redis-cli SETEX cache:user:1001:profile 300 '{"name":"John","email":"[email protected]","age":30}'
# Get from cache
redis-cli GET cache:user:1001:profile
# Check if key exists
redis-cli EXISTS cache:user:1001:profile
# Get TTL
redis-cli TTL cache:user:1001:profile
# Update cache
redis-cli SETEX cache:user:1001:profile 300 '{"name":"John","email":"[email protected]","age":31}'
# Delete from cache
redis-cli DEL cache:user:1001:profile
Cache with Hash Structure
#!/bin/bash
# hash-cache-example.sh
# Store user data as hash
redis-cli HSET user:1001 name "John Doe" email "[email protected]" age 30 last_login "2024-01-15T10:30:00Z"
# Get specific field
redis-cli HGET user:1001 name
# Get all fields
redis-cli HGETALL user:1001
# Update specific field
redis-cli HSET user:1001 age 31
# Check if field exists
redis-cli HEXISTS user:1001 email
# Set expiration
redis-cli EXPIRE user:1001 3600
2. Session Management
Session Storage
#!/bin/bash
# session-example.sh
# Create session
redis-cli HSET session:abc123 user_id 1001 login_time "2024-01-15T10:30:00Z" last_activity "2024-01-15T10:35:00Z" ip_address "192.168.1.100"
# Update last activity
redis-cli HSET session:abc123 last_activity "2024-01-15T10:40:00Z"
# Get session data
redis-cli HGETALL session:abc123
# Set session expiration (30 minutes)
redis-cli EXPIRE session:abc123 1800
# Check session validity
redis-cli TTL session:abc123
# Extend session
redis-cli EXPIRE session:abc123 1800
# Destroy session
redis-cli DEL session:abc123
3. Task Queue System
Simple Task Queue
#!/bin/bash
# task-queue-example.sh
# Add tasks to queue
redis-cli LPUSH task_queue "process_order_123"
redis-cli LPUSH task_queue "send_email_456"
redis-cli LPUSH task_queue "generate_report_789"
# Check queue length
redis-cli LLEN task_queue
# Process tasks (FIFO)
redis-cli RPOP task_queue
redis-cli RPOP task_queue
redis-cli RPOP task_queue
# Add priority tasks (high priority at the end)
redis-cli RPUSH task_queue "urgent_task_999"
# Process urgent task first
redis-cli RPOP task_queue
Best Practices
1. Key Naming Conventions
# Good: Descriptive and hierarchical
user:1001:profile
session:abc123:data
cache:product:123:details
queue:email:high_priority
# Bad: Unclear or too generic
key1
data
temp
2. Memory Management
# Set appropriate TTL for temporary data
SETEX cache:user:1001 300 "user_data"
# Use appropriate data types
# For objects: Use hashes instead of JSON strings
HSET user:1001 name "John" email "[email protected]"
# Monitor memory usage
INFO memory
3. Performance Optimization
# Use pipelines for multiple operations
redis-cli --pipe << EOF
SET key1 value1
SET key2 value2
SET key3 value3
EOF
# Use appropriate data structures
# For counters: Use INCR instead of GET + SET
INCR page_views
# For unique items: Use sets
SADD unique_visitors "user123"
Common Pitfalls and Solutions
1. Memory Issues
# ❌ Problem: Memory usage growing indefinitely
# Solution: Set appropriate TTL and monitor memory
# Set TTL for temporary data
SETEX temp_data 3600 "data"
# Monitor memory usage
INFO memory
CONFIG GET maxmemory
2. Key Expiration Issues
# ❌ Problem: Keys expiring unexpectedly
# Solution: Check TTL and use appropriate expiration
# Check TTL
TTL mykey
# Set appropriate expiration
EXPIRE mykey 3600 # 1 hour
# Use SETEX for immediate expiration
SETEX mykey 3600 "value"
3. Data Type Confusion
# ❌ Problem: Using wrong data type
# Solution: Choose appropriate data type for use case
# For simple key-value: Use strings
SET user:1001:name "John"
# For objects: Use hashes
HSET user:1001 name "John" email "[email protected]"
# For lists: Use lists
LPUSH tasks "task1" "task2"
# For unique items: Use sets
SADD tags "redis" "database"
Conclusion
Redis is a powerful, versatile in-memory data store that excels in caching, session management, and real-time applications. By understanding:
- What Redis is and its key features
- Why it's valuable for high-performance applications
- How to use its rich data structures and operations
You can leverage Redis to build fast, scalable applications. Redis's simplicity and performance make it an excellent choice for a wide range of use cases, from simple caching to complex real-time systems.
Next Steps
- Practice with different data types and operations
- Learn about Redis configuration and optimization
- Move on to Chapter 2: Installation and Configuration
This tutorial is part of the Redis Mastery series by syscook.dev