redis-best-practices

Redis development best practices for caching, data structures, and high-performance operations. Covers five core data structures (strings, hashes, lists, sets, sorted sets) plus streams, with command examples and use-case guidance for each Includes three caching patterns (cache-aside, write-through, invalidation) with pseudo-code and TTL strategies to prevent thundering herd Addresses high availability via replication, Sentinel, and cluster configuration with hash tags for key distribution Provides transaction and Lua scripting patterns for atomic operations, plus pub/sub messaging, persistence (RDB/AOF), and security hardening Covers monitoring, connection pooling, and performance optimization techniques including pipelining and memory management

INSTALLATION
npx skills add https://github.com/mindrally/skills --skill redis-best-practices
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

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 examples

user:1234:profile

user:1234:sessions

order:5678:items

cache:api:products:list

queue:email:pending

session:abc123def456

rate_limit:api:user:1234

Data Structures

Strings

  • Use for simple key-value storage, counters, and caching
  • Consider using MGET/MSET for batch operations
# Simple caching

SET cache:user:1234 '{"name":"John","email":"john@example.com"}' EX 3600

# Counters

INCR stats:pageviews:homepage

INCRBY stats:downloads:file123 5

# Atomic operations

SETNX lock:resource:456 "owner:abc" EX 30

Hashes

  • Use for objects with multiple fields
  • More memory-efficient than multiple string keys
  • Supports partial updates
# Store user profile

HSET user:1234 name "John Doe" email "john@example.com" created_at "2024-01-15"

# Get specific fields

HGET user:1234 email

HMGET user:1234 name email

# Increment numeric fields

HINCRBY user:1234 login_count 1

# Get all fields

HGETALL user:1234

Lists

  • Use for queues, recent items, and activity feeds
  • Consider blocking operations for queue consumers
# Message queue

LPUSH queue:emails '{"to":"user@example.com","subject":"Welcome"}'

RPOP queue:emails

# Blocking pop for workers

BRPOP queue:emails 30

# Recent activity (keep last 100)

LPUSH user:1234:activity "viewed product 567"

LTRIM user:1234:activity 0 99

# Get recent items

LRANGE user:1234:activity 0 9

Sets

  • Use for unique collections, tags, and relationships
  • Supports set operations (union, intersection, difference)
# User tags/interests

SADD user:1234:interests "technology" "music" "travel"

# Check membership

SISMEMBER user:1234:interests "music"

# Find common interests

SINTER user:1234:interests user:5678:interests

# Online users tracking

SADD online:users "user:1234"

SREM online:users "user:1234"

SMEMBERS online:users

Sorted Sets

  • Use for leaderboards, priority queues, and time-series data
  • Elements sorted by score
# Leaderboard

ZADD leaderboard:game1 1500 "player:123" 2000 "player:456" 1800 "player:789"

# Get top 10

ZREVRANGE leaderboard:game1 0 9 WITHSCORES

# Get player rank

ZREVRANK leaderboard:game1 "player:123"

# Time-based data (score = timestamp)

ZADD events:user:1234 1705329600 "login" 1705330000 "purchase"

# Get events in time range

ZRANGEBYSCORE events:user:1234 1705329600 1705333200

Streams

  • Use for event streaming and log data
  • Supports consumer groups for distributed processing
# Add events to stream

XADD events:orders * customer_id 1234 product_id 567 amount 99.99

# Read from stream

XREAD COUNT 10 STREAMS events:orders 0

# Consumer groups

XGROUP CREATE events:orders order-processors $ MKSTREAM

XREADGROUP GROUP order-processors worker1 COUNT 10 STREAMS events:orders >

# Acknowledge processed messages

XACK events:orders order-processors 1234567890-0

Caching Patterns

Cache-Aside Pattern

# Pseudo-code for cache-aside

def 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 cache

DEL cache:user:1234

# Delete by pattern (use with caution in production)

# Use SCAN instead of KEYS for large datasets

SCAN 0 MATCH cache:user:* COUNT 100

# Tag-based invalidation using sets

SADD cache:tags:user:1234 "cache:user:1234:profile" "cache:user:1234:orders"

# Invalidate all related caches

SMEMBERS cache:tags:user:1234

# Then delete each key

Expiration 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 expiration

SET cache:data:123 "value" EX 3600

# Set expiration on existing key

EXPIRE cache:data:123 3600

# Check TTL

TTL cache:data:123

# Persist key (remove expiration)

PERSIST cache:data:123

Memory Management

# Check memory usage

INFO memory

# Get key memory usage

MEMORY USAGE cache:large:object

# Configure max memory policy

CONFIG SET maxmemory 2gb

CONFIG SET maxmemory-policy allkeys-lru

Transactions and Atomicity

MULTI/EXEC Transactions

# Transaction block

MULTI

INCR stats:views

LPUSH recent:views "page:123"

EXEC

# Watch for optimistic locking

WATCH user:1234:balance

balance = GET user:1234:balance

MULTI

SET user:1234:balance (balance - 100)

EXEC

Lua Scripts

  • Use for complex atomic operations
  • Scripts execute atomically
-- Rate limiting script

local 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 0

end

redis.call('INCR', key)

if current == 0 then

    redis.call('EXPIRE', key, window)

end

return 1
# Execute Lua script

EVAL "return redis.call('GET', KEYS[1])" 1 mykey

Pub/Sub and Messaging

# Publisher

PUBLISH channel:notifications '{"type":"alert","message":"New order"}'

# Subscriber

SUBSCRIBE channel:notifications

# Pattern subscription

PSUBSCRIBE channel:*

High Availability

Replication

  • Use replicas for read scaling
  • Configure proper persistence on master
# On replica

REPLICAOF master_host 6379

# Check replication status

INFO replication

Redis 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 slot

SET {user:1234}:profile "data"

SET {user:1234}:settings "data"

Persistence

RDB Snapshots

# Manual snapshot

BGSAVE

# Configure automatic snapshots

CONFIG SET save "900 1 300 10 60 10000"

AOF (Append-Only File)

# Enable AOF

CONFIG SET appendonly yes

CONFIG SET appendfsync everysec

# Rewrite AOF

BGREWRITEAOF

Security

  • Require authentication
  • Use TLS for connections
  • Bind to specific interfaces
  • Disable dangerous commands
# Set password

CONFIG SET requirepass "your_strong_password"

# Authenticate

AUTH your_strong_password

# Rename dangerous commands (in redis.conf)

rename-command FLUSHALL ""

rename-command FLUSHDB ""

rename-command KEYS ""

Monitoring

# Server info

INFO

# Memory stats

INFO memory

# Client connections

CLIENT LIST

# Slow log

SLOWLOG GET 10

# Monitor commands (debug only)

MONITOR

# Key count per database

INFO keyspace

Connection Management

  • Use connection pooling
  • Set appropriate timeouts
  • Handle reconnection gracefully
# Python example with connection pool

import redis

pool = 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()
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card