redis-best-practices
mindrally/skills
Redis development best practices for caching, data structures, and high-performance key-value operations
...Expand allAbout redis-best-practices
The Redis Best Practices skill provides comprehensive guidance for effectively using Redis as an in-memory data store. It covers optimal patterns for caching, session storage, real-time analytics, and message queuing while helping developers avoid common pitfalls and performance issues. This skill addresses the challenge of leveraging Redis's full potential by teaching proper data structure selection, key naming conventions, and architectural patterns that ensure scalability and maintainability.
The skill focuses on Redis's five core data structures—strings, hashes, lists, sets, and sorted sets—plus the newer streams feature for event processing. It provides practical code examples for each structure, demonstrating when and how to use atomic operations, batch commands, and blocking operations. Key topics include implementing efficient cache-aside patterns, designing leaderboards with sorted sets, building message queues with lists, and handling distributed event processing with consumer groups. The guidance emphasizes memory efficiency, proper expiration policies, and consistent naming patterns that make Redis applications easier to debug and scale.
This skill is ideal for backend developers working with high-performance applications that require fast data access, DevOps engineers designing caching layers, and architects building real-time systems. Whether you're implementing session management, building a rate limiter, creating activity feeds, or designing distributed task queues, this skill provides battle-tested patterns and concrete examples that can be directly applied to production systems.
FAQ
What data structure should I use for a leaderboard?
Use sorted sets (ZADD, ZREVRANGE) where scores represent player rankings. Sorted sets automatically maintain order and support efficient rank queries and score-based range operations.
How do I implement proper cache expiration?
Set expiration times using the EX parameter with SET commands or use SETEX. Choose TTL values based on data volatility—shorter for frequently changing data (seconds to minutes), longer for static content (hours to days).
When should I use hashes instead of multiple string keys?
Use hashes when storing objects with multiple fields. Hashes are more memory-efficient than creating separate string keys for each field and allow partial updates without fetching the entire object.
What's the difference between RPOP and BRPOP for queues?
RPOP returns immediately with a value or null if the list is empty. BRPOP is a blocking operation that waits up to a specified timeout for an item to become available, making it ideal for worker processes that need to efficiently wait for new tasks.
How do I handle distributed processing with Redis Streams?
Use consumer groups with XGROUP CREATE and XREADGROUP. Multiple consumers can process messages in parallel, and Redis tracks which messages each consumer has received. Use XACK to acknowledge successful processing.
Redis Best Practices
Core Principles
- Use Redis for caching, session storage, real-time analytics, and message queuing
- Choose appropriate data structures for your use case
- Implement proper key naming conventions and expiration policies
- Design for high availability and persistence requirements
- Monitor memory usage and optimize for performance
Key Naming Conventions
- Use colons as namespace separators
- Include object type and identifier in key names
- Keep keys short but descriptive
- Use consistent naming patterns across your application
# Good key naming examplesuser:1234:profileuser:1234:sessionsorder:5678:itemscache:api:products:listqueue:email:pendingsession:abc123def456rate_limit:api:user:1234Data Structures
Strings
- Use for simple key-value storage, counters, and caching
- Consider using MGET/MSET for batch operations
# Simple cachingSET cache:user:1234 '{"name":"John","email":"[email protected]"}' EX 3600# CountersINCR stats:pageviews:homepageINCRBY stats:downloads:file123 5# Atomic operationsSETNX lock:resource:456 "owner:abc" EX 30Hashes
- Use for objects with multiple fields
- More memory-efficient than multiple string keys
- Supports partial updates
# Store user profileHSET user:1234 name "John Doe" email "[email protected]" created_at "2024-01-15"# Get specific fieldsHGET user:1234 emailHMGET user:1234 name email# Increment numeric fieldsHINCRBY user:1234 login_count 1# Get all fieldsHGETALL user:1234Lists
- Use for queues, recent items, and activity feeds
- Consider blocking operations for queue consumers
# Message queueLPUSH queue:emails '{"to":"[email protected]","subject":"Welcome"}'RPOP queue:emails# Blocking pop for workersBRPOP queue:emails 30# Recent activity (keep last 100)LPUSH user:1234:activity "viewed product 567"LTRIM user:1234:activity 0 99# Get recent itemsLRANGE user:1234:activity 0 9Sets
- Use for unique collections, tags, and relationships
- Supports set operations (union, intersection, difference)
# User tags/interestsSADD user:1234:interests "technology" "music" "travel"# Check membershipSISMEMBER user:1234:interests "music"# Find common interestsSINTER user:1234:interests user:5678:interests# Online users trackingSADD online:users "user:1234"SREM online:users "user:1234"SMEMBERS online:usersSorted Sets
- Use for leaderboards, priority queues, and time-series data
- Elements sorted by score
# LeaderboardZADD leaderboard:game1 1500 "player:123" 2000 "player:456" 1800 "player:789"# Get top 10ZREVRANGE leaderboard:game1 0 9 WITHSCORES# Get player rankZREVRANK leaderboard:game1 "player:123"# Time-based data (score = timestamp)ZADD events:user:1234 1705329600 "login" 1705330000 "purchase"# Get events in time rangeZRANGEBYSCORE events:user:1234 1705329600 1705333200Streams
- Use for event streaming and log data
- Supports consumer groups for distributed processing
# Add events to streamXADD events:orders * customer_id 1234 product_id 567 amount 99.99# Read from streamXREAD COUNT 10 STREAMS events:orders 0# Consumer groupsXGROUP CREATE events:orders order-processors $ MKSTREAMXREADGROUP GROUP order-processors worker1 COUNT 10 STREAMS events:orders ># Acknowledge processed messagesXACK events:orders order-processors 1234567890-0Caching Patterns
Cache-Aside Pattern
# Pseudo-code for cache-asidedef get_user(user_id): # Try cache first cached = redis.get(f"cache:user:{user_id}") if cached: return json.loads(cached) # Cache miss - fetch from database user = database.get_user(user_id) # Store in cache with expiration redis.setex(f"cache:user:{user_id}", 3600, json.dumps(user)) return user
Write-Through Pattern
def update_user(user_id, data): # Update database database.update_user(user_id, data) # Update cache redis.setex(f"cache:user:{user_id}", 3600, json.dumps(data))
Cache Invalidation
# Delete specific cacheDEL cache:user:1234# Delete by pattern (use with caution in production)# Use SCAN instead of KEYS for large datasetsSCAN 0 MATCH cache:user:* COUNT 100# Tag-based invalidation using setsSADD cache:tags:user:1234 "cache:user:1234:profile" "cache:user:1234:orders"# Invalidate all related cachesSMEMBERS cache:tags:user:1234# Then delete each keyExpiration and Memory Management
TTL Best Practices
- Always set TTL on cache keys
- Use jitter to prevent thundering herd
- Consider sliding expiration for session data
# Set with expirationSET cache:data:123 "value" EX 3600# Set expiration on existing keyEXPIRE cache:data:123 3600# Check TTLTTL cache:data:123# Persist key (remove expiration)PERSIST cache:data:123Memory Management
# Check memory usageINFO memory# Get key memory usageMEMORY USAGE cache:large:object# Configure max memory policyCONFIG SET maxmemory 2gbCONFIG SET maxmemory-policy allkeys-lruTransactions and Atomicity
MULTI/EXEC Transactions
# Transaction blockMULTIINCR stats:viewsLPUSH recent:views "page:123"EXEC# Watch for optimistic lockingWATCH user:1234:balancebalance = GET user:1234:balanceMULTISET user:1234:balance (balance - 100)EXECLua Scripts
- Use for complex atomic operations
- Scripts execute atomically
-- Rate limiting scriptlocal key = KEYS[1]local limit = tonumber(ARGV[1])local window = tonumber(ARGV[2])local current = tonumber(redis.call('GET', key) or '0')if current >= limit then return 0endredis.call('INCR', key)if current == 0 then redis.call('EXPIRE', key, window)endreturn 1
# Execute Lua scriptEVAL "return redis.call('GET', KEYS[1])" 1 mykeyPub/Sub and Messaging
# PublisherPUBLISH channel:notifications '{"type":"alert","message":"New order"}'# SubscriberSUBSCRIBE channel:notifications# Pattern subscriptionPSUBSCRIBE channel:*High Availability
Replication
- Use replicas for read scaling
- Configure proper persistence on master
# On replicaREPLICAOF master_host 6379# Check replication statusINFO replicationRedis Sentinel
- Use for automatic failover
- Deploy at least 3 Sentinel instances
Redis Cluster
- Use for horizontal scaling
- Data automatically sharded across nodes
- Use hash tags for related keys
# Hash tags ensure keys go to same slotSET {user:1234}:profile "data"SET {user:1234}:settings "data"Persistence
RDB Snapshots
# Manual snapshotBGSAVE# Configure automatic snapshotsCONFIG SET save "900 1 300 10 60 10000"AOF (Append-Only File)
# Enable AOFCONFIG SET appendonly yesCONFIG SET appendfsync everysec# Rewrite AOFBGREWRITEAOFSecurity
- Require authentication
- Use TLS for connections
- Bind to specific interfaces
- Disable dangerous commands
# Set passwordCONFIG SET requirepass "your_strong_password"# AuthenticateAUTH your_strong_password# Rename dangerous commands (in redis.conf)rename-command FLUSHALL ""rename-command FLUSHDB ""rename-command KEYS ""Monitoring
# Server infoINFO# Memory statsINFO memory# Client connectionsCLIENT LIST# Slow logSLOWLOG GET 10# Monitor commands (debug only)MONITOR# Key count per databaseINFO keyspaceConnection Management
- Use connection pooling
- Set appropriate timeouts
- Handle reconnection gracefully
# Python example with connection poolimport redispool = redis.ConnectionPool( host='localhost', port=6379, max_connections=50, socket_timeout=5, socket_connect_timeout=5)redis_client = redis.Redis(connection_pool=pool)
Performance Tips
- Use pipelining for batch operations
- Avoid large keys (>100KB values)
- Use SCAN instead of KEYS in production
- Monitor and optimize memory usage
- Consider using RedisJSON for complex JSON operations
# Pipeline example (pseudo-code)pipe = redis.pipeline()pipe.get("key1")pipe.get("key2")pipe.set("key3", "value")results = pipe.execute() Install redis-best-practices
Download and extract the skill files to your .claude/skills/ directory.
Download ZIPClone the repository and copy the skill files to your project.
git clone https://github.com/Mindrally/skills/blob/main/redis-best-practices/SKILL.md # Copy SKILL.md to your .claude/skills/ directory
Copy





Home
