DEV Community

ZNY
ZNY

Posted on

Redis Complete Guide in 2026: Caching Performance and Beyond

Redis Complete Guide in 2026

Published: 2026-05-04

Redis is the world's most popular in-memory data store, essential for caching, session management, real-time analytics, and message queuing. This comprehensive guide covers Redis data types, persistence, clustering, sentinel, Lua scripting, pub/sub, streams, security, performance tuning, and production deployment best practices.

Introduction to Redis

What is Redis?


┌─────────────────────────────────────────────────────────┐

│  Redis (Remote Dictionary Server)                                │

│                                                          │

│  • In-memory data structure store                       │

│  • Key-value database                                  │

│  • Cache, message broker, and queue                    │

│  • Sub-millisecond response times                       │

│  • Supports data structures: strings, lists,         │

│    sets, sorted sets, hashes, bitmaps, hyperloglogs,    │

│    geospatial indexes, streams                         │

│                                                          │

│  Common Use Cases:                                       │

│  • Caching (API responses, database queries)          │

│  • Session storage                                     │

│  • Real-time analytics                                 │

│  • Rate limiting                                       │

│  • Message queues                                      │

│  • Distributed locks                                    │

└─────────────────────────────────────────────────────────┘

Enter fullscreen mode Exit fullscreen mode

Installation


brew install redis

brew services start redis

# Ubuntu/Debian

sudo apt update

sudo apt install redis-server

docker run -d --name redis -p 6379:6379 redis:latest

# Redis with persistence

docker run -d --name redis \

-p 6379:6379 \

-v redis-data:/data \

redis:latest \

redis-server --appendonly yes

redis-cli ping  # Should return PONG

Enter fullscreen mode Exit fullscreen mode

Data Types

Strings


# Basic string operations

SET user:123:name "Alice"

GET user:123:name

# With expiry (seconds)

SET session:abc123 "data" EX 3600

# With expiry (milliseconds)

SET token:xyz PX 3000

# Get remaining TTL

TTL session:abc123

# Set if not exists (atomic)

SETNX lock:resource:1 "locked"

# Multiple values

MSET user:1:name "Alice" user:1:email "alice@example.com" user:1:age "30"

MGET user:1:name user:1:email

# Increment/decrement

INCR pageviews:home

INCRBY pageviews:home 10

DECR counter

INCRBYFLOAT price:product:1 0.99

# String length

STRLEN user:1:name

# Get range

GETRANGE user:1:bio 0 10

# Set range

SETRANGE user:1:bio 0 "Hello"

Enter fullscreen mode Exit fullscreen mode

Lists


LPUSH notifications "New order received"

RPUSH notifications "Order shipped"

LPOP notifications

RPOP notifications

# Blocking pop (for queues)

BLPOP notifications 0  # Wait forever

BRPOP notifications 5   # Wait 5 seconds

# List length

LLEN notifications

LRANGE notifications 0 9

# Trim (keep only first 100)

LTRIM notifications 0 99

LINSERT notifications BEFORE "Order shipped" "Order confirmed"

# Index access

LINDEX notifications 0

Enter fullscreen mode Exit fullscreen mode

Sets


# Add/remove/members

SADD tags:article:1 "python" "redis" "database"

SREM tags:article:1 "database"

SMEMBERS tags:article:1

# Check membership

SISMEMBER tags:article:1 "python"

SCARD tags:article:1

# Random members

SRANDMEMBER tags:article:1 3      # 3 random without removing

SPOP tags:article:1 2             # 2 random AND remove

# Set operations

SADD set:a 1 2 3 4

SADD set:b 3 4 5 6

SINTER set:a set:b      # Intersection: 3, 4

SUNION set:a set:b      # Union: 1,2,3,4,5,6

SDIFF set:a set:b       # Difference: 1, 2

# Store results

SINTERSTORE set:intersection set:a set:b

Enter fullscreen mode Exit fullscreen mode

Sorted Sets


# Add with score (for leaderboards)

ZADD leaderboard 1000 "alice"

ZADD leaderboard 950 "bob"

ZADD leaderboard 1100 "charlie"

# Get rank (0 = highest)

ZREVRANK leaderboard "alice"     # 1 (charlie is 0)

# Get score

ZSCORE leaderboard "alice"       # 1000

ZREVRANGE leaderboard 0 9 WITHSCORES

# Bottom 10

ZRANGE leaderboard 0 9 WITHSCORES

# Score range

ZRANGEBYSCORE leaderboard 900 1000

# Count in range

ZCOUNT leaderboard 900 1000

# Increment score

ZINCRBY leaderboard 50 "alice"  # Now 1050

# Remove by rank

ZREMRANGEBYRANK leaderboard 0 9  # Remove bottom 10

Enter fullscreen mode Exit fullscreen mode

Hashes


# Hash operations

HSET user:123 name "Alice" email "alice@example.com" age "30"

HGET user:123 name

HGETALL user:123

HMGET user:123 name email

HMSET user:456 name "Bob" email "bob@example.com"

HINCRBY user:123 age 1           # Increment age

HEXISTS user:123 email           # Check if field exists

HDEL user:123 age                # Delete field

HLEN user:123                    # Number of fields

HKEYS user:123                   # All field names

HVALS user:123                   # All values

Enter fullscreen mode Exit fullscreen mode

Bitmaps


# Bitmap for user activity tracking

SETBIT user:123:login:2024 0 1    # Day 0 (Jan 1) - user logged in

SETBIT user:123:login:2024 5 1   # Day 5 (Jan 6)

# Check if active on day 5

GETBIT user:123:login:2024 5

# Count active days

BITCOUNT user:123:login:2024

# Find first set bit

BITPOS user:123:login:2024 1     # First day with login

# Bitwise operations

BITOP AND user:and:123 user:123:login:2024 user:456:login:2024

Enter fullscreen mode Exit fullscreen mode

HyperLogLog


# HyperLogLog for approximate unique counts

PFADD visitors:daily "user:123" "user:456" "user:789"

PFADD visitors:daily "user:123" "user:456"  # Duplicate - no effect

PFCOUNT visitors:daily            # Approximate unique count

# Merge multiple days

PFMERGE visitors:week visitors:daily:2024-01-01 visitors:daily:2024-01-02

PFCOUNT visitors:week

Enter fullscreen mode Exit fullscreen mode

Geospatial


# Add locations

GEOADD locations -122.4194 37.7749 "san-francisco"

GEOADD locations -122.2711 37.8044 "oakland"

GEOADD locations -121.8863 37.3382 "san-jose"

# Distance between locations

GEODIST locations "san-francisco" "san-jose" km

# Find locations within radius

GEORADIUS locations -122.4194 37.7749 50 km WITHDIST ASC COUNT 10

# Get position

GEOPOS locations "san-francisco"

# Find city containing point

GEOSEARCH locations FROMLONLAT -122.4194 37.7749 BYRADIUS 50 km

Enter fullscreen mode Exit fullscreen mode

Persistence

RDB Snapshots


# redis.conf

save 900 1      # After 1 change in 900 seconds

save 300 100     # After 100 changes in 300 seconds

save 60 10000    # After 10000 changes in 60 seconds

# Disable RDB (if using AOF)

# Snapshot file location

dbfilename dump.rdb

dir /var/lib/redis

# Manual save

BGSAVE          # Background save

LASTSAVE         # Timestamp of last successful save

# Check if saving in progress

INFO persistence

Enter fullscreen mode Exit fullscreen mode

AOF (Append-Only File)


# redis.conf

appendonly yes

appendfilename "appendonly.aof"

# fsync policy

appendfsync always      # Every write (slow, most durable)

appendfsync everysec    # Every second (default, balanced)

appendfsync no          # Let OS decide (fastest, risky)

# AOF rewrite (compact)

BGREWRITEAOF

# Check AOF

redis-cli info | grep aof

Enter fullscreen mode Exit fullscreen mode

Hybrid Persistence (Redis 7.0+)


# redis.conf - Redis 7.0+ multi-part AOF

aof-use-rdb-preamble yes  # Use RDB for base, AOF for增量

Enter fullscreen mode Exit fullscreen mode

Lua Scripting

Basic Scripts


-- Simple Lua script (atomic execution)

-- KEYS[1] = user key

-- ARGV[1] = increment amount

local current = redis.call('GET', KEYS[1])

if current == false then

current = 0

current = tonumber(current)

local increment = tonumber(ARGV[1])

local new_value = current + increment

redis.call('SET', KEYS[1], new_value)

return new_value

-- Usage with redis-cli

-- redis-cli --eval increment.lua user:123:balance , 100

Enter fullscreen mode Exit fullscreen mode

-- Distributed lock in Lua

-- KEYS[1] = lock key

-- ARGV[1] = lock value (unique identifier)

-- ARGV[2] = TTL in milliseconds

local lock = redis.call('SET', KEYS[1], ARGV[1], 'NX', 'PX', ARGV[2])

if lock == 'OK' then

Enter fullscreen mode Exit fullscreen mode

-- Rate limiter (sliding window)

-- KEYS[1] = rate limit key

-- ARGV[1] = window size in ms

-- ARGV[2] = max requests per window

local key = KEYS[1]

local window = tonumber(ARGV[1])

local limit = tonumber(ARGV[2])

local now = redis.call('TIME')[1]

local window_start = now - window

-- Remove old entries

redis.call('ZREMRANGEBYSCORE', key, '-inf', window_start)

-- Count current requests

local count = redis.call('ZCARD', key)

if count >= limit then

redis.call('ZADD', key, now, now .. '-' .. math.random())

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

Enter fullscreen mode Exit fullscreen mode

Script Management


# Load script once, use hash

SCRIPT LOAD "return redis.call('GET', KEYS[1])"

# Returns script hash: "a4203f..."

# Execute by hash

EVALSHA "a4203f..." 1 user:123

# Check if script exists

SCRIPT EXISTS "a4203f..."

# Flush script cache (rarely needed)

SCRIPT FLUSH

Enter fullscreen mode Exit fullscreen mode

Pub/Sub

Basic Pub/Sub


# Terminal 1 - Subscribe to channel

SUBSCRIBE notifications

# OR multiple channels

PSUBSCRIBE notifications.*

# Terminal 2 - Publish

PUBLISH notifications "Hello, subscribers!"

PUBLISH notifications:urgent "Critical alert!"

Enter fullscreen mode Exit fullscreen mode

Pattern Subscription


-- Lua script for reliable queue using Pub/Sub

-- Publisher

redis.call('PUBLISH', channel, message)

-- Subscriber with acknowledgment

while true do

local msg = redis.call('SUBSCRIBE', channel)

-- Process message

-- ACK only after successful processing

Enter fullscreen mode Exit fullscreen mode

Redis Streams (for Reliable Messaging)


# Add to stream

XADD mystream * field1 value1 field2 value2

# * = auto-generate ID

# Read from beginning

XRANGE mystream - +

# Read new messages

XREAD STREAMS mystream $

# Consumer groups (for distributed processing)

XGROUP CREATE mystream mygroup $ MKSTREAM

# Read as consumer in group

XREADGROUP GROUP mygroup consumer1 STREAMS mystream ">"

# Acknowledge message

XACK mystream mygroup 1526564898035-0

# Pending messages (unacknowledged)

XPENDING mystream mygroup

# Claim pending messages

XCLAIM mystream mygroup consumer2 0 1526564898035-0

Enter fullscreen mode Exit fullscreen mode

Clustering

Cluster Configuration


# redis.conf for cluster node

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 15000

cluster-replica-validity-factor 2

# Minimum cluster size

cluster-require-full-coverage yes

cluster-migration-barrier 1

Enter fullscreen mode Exit fullscreen mode

Creating a Cluster


# Create cluster (redis-cli >= 7.0)

redis-cli --cluster create \

10.0.0.1:6379 \

10.0.0.2:6379 \

10.0.0.3:6379 \

10.0.0.4:6379 \

10.0.0.5:6379 \

10.0.0.6:6379 \

--cluster-replicas 1

# 3 masters + 3 slaves (1 replica each)

# Check cluster info

redis-cli -c -h 10.0.0.1 cluster info

# List nodes

redis-cli -c -h 10.0.0.1 cluster nodes

Enter fullscreen mode Exit fullscreen mode

Cluster Commands


# Connect to cluster

redis-cli -c -h 10.0.0.1

# Auto-rebalance slots

redis-cli --cluster rebalance 10.0.0.1:6379

# Add new node

redis-cli --cluster add-node 10.0.0.7:6379 10.0.0.1:6379

# Add replica

redis-cli --cluster add-node 10.0.0.8:6379 10.0.0.1:6379 --cluster-slave --cluster-master-id <node-id>

# Remove node

redis-cli --cluster del-node 10.0.0.1:6379 <node-id>

# Reshard slots

redis-cli --cluster reshard 10.0.0.1:6379

Enter fullscreen mode Exit fullscreen mode

Key Hash Tags (for Multi-Key Operations)


# Force keys to same slot (for transactions, sorted sets)

# Use braces: {user:123}:cart

# All {user:123}:* keys go to same slot

SET {user:123}:cart "item1,item2"

SET {user:123}:wishlist "item3,item4"

# Now MGET across multiple keys is possible (same slot)

MGET {user:123}:cart {user:123}:wishlist

Enter fullscreen mode Exit fullscreen mode

Sentinel (High Availability)

Sentinel Configuration


# sentinel.conf

sentinel monitor mymaster 10.0.0.1 6379 2   # Quorum: 2

sentinel down-after-milliseconds mymaster 5000

sentinel failover-timeout mymaster 60000

sentinel parallel-syncs mymaster 1

# Auth for master

sentinel auth-pass mymaster mypassword

# Start sentinel

redis-sentinel /path/to/sentinel.conf

# Or with redis-server

redis-server /path/to/sentinel.conf --sentinel

Enter fullscreen mode Exit fullscreen mode

Sentinel Commands


# Check sentinel info

redis-cli -p 26379 INFO

# List monitored masters

redis-cli -p 26379 SENTINEL masters

# Get master details

redis-cli -p 26379 SENTINEL master mymaster

# Get master IP (for connection)

redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster

# Force failover

redis-cli -p 26379 SENTINEL failover mymaster

# Check for replica lag

redis-cli -p 26379 SENTINEL replicas mymaster

Enter fullscreen mode Exit fullscreen mode

Application Connection


// Node.js with Sentinel

const Redis = require('ioredis');

const RedisSentinel = require('ioredis-sentinel');

const sentinel = new RedisSentinel(['10.0.0.1:26379', '10.0.0.2:26379']);

const redis = new Redis({

sentinels: [{ host: '10.0.0.1', port: 26379 }],

name: 'mymaster',

password: 'mypassword',

enableReadyCheck: true,

connectTimeout: 10000

redis.on('error', (err) => {

console.error('Redis error:', err);

Enter fullscreen mode Exit fullscreen mode

Security

Authentication


# redis.conf

requirepass mystrongpassword

# Or via command

CONFIG SET requirepass "mystrongpassword"

AUTH mystrongpassword

# For specific commands

# ACL (Redis 6.0+)

ACL LIST                    # List all ACL rules

ACL SETUSER alice +GET +SET ~items:* >password123

ACL SETUSER bob +GET ~items:read:* -@all

Enter fullscreen mode Exit fullscreen mode

TLS


# redis.conf

tls-port 6380

port 0                     # Disable non-TLS

tls-cert-file /path/to/redis.crt

tls-key-file /path/to/redis.key

tls-ca-cert-file /path/to/ca.crt

# Require TLS

tls-auth-clients no       # Skip client cert validation

tls-auth-clients yes      # Require client cert

Enter fullscreen mode Exit fullscreen mode

Network Security


# Bind to specific IP

bind 127.0.0.1 10.0.0.1

# Disable dangerous commands

rename-command FLUSHDB ""

rename-command FLUSHALL ""

rename-command DEBUG ""

rename-command CONFIG "CONFIG_9sd8f7s"

# Set max memory

maxmemory 2gb

maxmemory-policy allkeys-lru

Enter fullscreen mode Exit fullscreen mode

Performance Tuning

Memory Optimization


# Memory usage info

redis-cli INFO memory

redis-cli MEMORY STATS

# Check big keys

redis-cli --bigkeys

# Find memory usage of key

redis-cli DEBUG OBJECT ENCODING user:123

redis-cli MEMORY USAGE user:123

# Eviction policies

# noeviction: Return error when OOM

# allkeys-lru: Remove least recently used

# allkeys-lfu: Remove least frequently used

# volatile-lru: LRU only for keys with TTL

# volatile-lfu: LFU only for keys with TTL

# allkeys-random: Random removal

# volatile-random: Random with TTL

# volatile-ttl: Remove keys with shortest TTL

maxmemory-policy allkeys-lru

Enter fullscreen mode Exit fullscreen mode

Pipeline and Transactions


# Pipeline (batch commands)

redis-cli --pipe <<EOF

SET key1 value1

SET key2 value2

INCR counter

# Or with redis-py

pipe = redis.pipeline()

pipe.set('key1', 'value1')

pipe.set('key2', 'value2')

pipe.incr('counter')

results = pipe.execute()

# Transactions (MULTI/EXEC)

SET key1 value1

INCR counter

# WATCH for optimistic locking

WATCH user:123:balance

balance = GET user:123:balance

# ... check balance ...

SET user:123:balance $new_balance

EXEC    # Fails if key changed

Enter fullscreen mode Exit fullscreen mode

Slow Queries


# Enable slow log

slowlog-log-slower-than 10000   # 10ms in microseconds

slowlog-max-len 128            # Keep last 128 entries

# View slow queries

SLOWLOG GET 10

# Current configuration

SLOWLOG RESET

Enter fullscreen mode Exit fullscreen mode

Caching Patterns

Cache-Aside


async function getUser(userId) {

// Try cache first

const cached = await redis.get(`user:${userId}`);

if (cached) {

return JSON.parse(cached);

// Cache miss - fetch from DB

const user = await db.getUser(userId);

// Store in cache with TTL

await redis.setex(`user:${userId}`, 3600, JSON.stringify(user));

return user;

async function updateUser(userId, data) {

// Update DB

await db.updateUser(userId, data);

// Invalidate cache

await redis.del(`user:${userId}`);

Enter fullscreen mode Exit fullscreen mode

Write-Through


async function createUser(userId, data) {

// Write to both DB and cache simultaneously

await Promise.all([

db.createUser(userId, data),

redis.setex(`user:${userId}`, 3600, JSON.stringify(data))

return data;

Enter fullscreen mode Exit fullscreen mode

Distributed Lock


async function acquireLock(key, ttlMs = 30000) {

const lockValue = uuid.v4();

const acquired = await redis.set(key, lockValue, 'PX', ttlMs, 'NX');

if (acquired === 'OK') {

return lockValue;

return null;

async function releaseLock(key, lockValue) {

// Lua script for atomic check-and-delete

const script = `

if redis.call("get", KEYS[1]) == ARGV[1] then

return redis.call("del", KEYS[1])

await redis.eval(script, 1, key, lockValue);

Enter fullscreen mode Exit fullscreen mode

Rate Limiter


async function checkRateLimit(userId, limit = 100, windowSecs = 60) {

const key = `ratelimit:${userId}`;

const now = Date.now();

const windowStart = now - (windowSecs * 1000);

const multi = redis.multi();

multi.zremrangebyscore(key, '-inf', windowStart);

multi.zadd(key, now, `${now}`);

multi.zcard(key);

multi.expire(key, windowSecs);

const results = await multi.exec();

const requestCount = results[2];

allowed: requestCount <= limit,

remaining: Math.max(0, limit - requestCount),

resetAt: now + (windowSecs * 1000)

Enter fullscreen mode Exit fullscreen mode

Real-World Patterns

Session Store


// Express session with Redis

const session = require('express-session');

const RedisStore = require('connect-redis').default;

const { createClient } = require('redis');

const redisClient = createClient({

url: process.env.REDIS_URL

await redisClient.connect();

app.use(session({

store: new RedisStore({ client: redisClient }),

secret: process.env.SESSION_SECRET,

name: 'sessionId',

resave: false,

saveUninitialized: false,

secure: true,

httpOnly: true,

maxAge: 7 * 24 * 60 * 60 * 1000  // 7 days

Enter fullscreen mode Exit fullscreen mode

Job Queue


// Simple job queue with Redis

async function enqueueJob(queueName, jobData) {

const jobId = uuid.v4();

const job = {

data: jobData,

status: 'pending',

createdAt: Date.now()

await redis.hset(`job:${jobId}`, job);

await redis.rpush(`queue:${queueName}`, jobId);

return jobId;

async function dequeueJob(queueName) {

const jobId = await redis.lpop(`queue:${queueName}`);

if (!jobId) return null;

const job = await redis.hgetall(`job:${jobId}`);

job.status = 'processing';

await redis.hset(`job:${jobId}`, 'status', 'processing');

return { jobId, job };

async function completeJob(jobId, result) {

await redis.hset(`job:${jobId}`, {

status: 'completed',

completedAt: Date.now(),

result: JSON.stringify(result)

async function failJob(jobId, error) {

await redis.hset(`job:${jobId}`, {

status: 'failed',

failedAt: Date.now(),

error: error.message

Enter fullscreen mode Exit fullscreen mode

Leaderboard


// Game leaderboard

async function submitScore(userId, gameId, score) {

const key = `leaderboard:${gameId}`;

await redis.zadd(key, score, `${userId}`);

async function getTopScores(gameId, count = 10) {

const key = `leaderboard:${gameId}`;

return redis.zrevrange(key, 0, count - 1, 'WITHSCORES');

async function getUserRank(userId, gameId) {

const key = `leaderboard:${gameId}`;

const rank = await redis.zrevrank(key, `${userId}`);

const score = await redis.zscore(key, `${userId}`);

return { rank: rank + 1, score };

async function getAroundMe(userId, gameId, range = 5) {

const key = `leaderboard:${gameId}`;

const rank = await redis.zrevrank(key, `${userId}`);

const start = Math.max(0, rank - range);

const end = rank + range;

const results = await redis.zrevrange(key, start, end, 'WITHSCORES');

return results;

Enter fullscreen mode Exit fullscreen mode

Checklist

  • [ ] Install and configure Redis properly

  • [ ] Use appropriate data types for your use case

  • [ ] Enable persistence (RDB + AOF recommended)

  • [ ] Set up authentication and TLS in production

  • [ ] Configure memory eviction policy

  • [ ] Use connection pooling in applications

  • [ ] Implement cache-aside pattern with TTL

  • [ ] Use pipelining for batch operations

  • [ ] Implement distributed locks for critical sections

  • [ ] Set up Redis Sentinel for high availability

  • [ ] Use Redis Cluster for horizontal scaling

  • [ ] Monitor memory usage and slow queries

  • [ ] Use HyperLogLog for approximate unique counts

  • [ ] Implement rate limiting with sorted sets

  • [ ] Use streams for reliable message queuing

  • [ ] Configure proper key expiration

  • [ ] Monitor and tune slow log threshold

  • [ ] Back up RDB snapshots regularly

  • [ ] Document key naming conventions

  • [ ] Test failover and recovery procedures

Conclusion

Redis is essential for modern application architecture:

  1. Data Types — Strings, Lists, Sets, Sorted Sets, Hashes, Bitmaps, Geospatial

  2. Persistence — RDB snapshots, AOF, hybrid mode

  3. Lua Scripting — Atomic operations, complex logic

  4. Pub/Sub — Real-time messaging, notifications

  5. Streams — Reliable message queues, consumer groups

  6. Clustering — Horizontal scaling, sharding

  7. Sentinel — High availability, automatic failover

  8. Security — Authentication, TLS, ACL

  9. Performance — Pipelining, memory optimization

  10. Patterns — Caching, locks, rate limiting, sessions

Redis powers the fastest applications in the world.

Rating: 5/5 for Redis complete guide.

This article is for educational purposes.

Categories: Redis, Database, Caching, NoSQL, In-Memory, Performance, Distributed Systems, Python, Node.js

Tags: Redis tutorial, Redis data structures, caching, Redis cluster, pub/sub, Lua scripting, Redis performance


This article contains affiliate links. If you sign up through the links above, I may earn a commission at no additional cost to you.

Ready to Build Your AI Business?

Get started with Systeme.io for free — All-in-one platform for building your online business with AI tools.

Top comments (0)