redis
Redis
Caching, data structures, and real-time patterns.
Key Naming Conventions
object-type:id:field # Colon-separated hierarchy
user:1001:profile # User profile
cache:api:/v2/products # API response cache
session:abc123 # Session data
ratelimit:ip:10.0.0.1 # Rate limit counter
lock:order:7890 # Distributed lock
Keep keys short but readable. Colons are convention, not syntax. Avoid KEYS in production — use SCAN.
CLI Basics
redis-cli
redis-cli -h hostname -p 6379 -a password
redis-cli --tls -h hostname -p 6380 # TLS connection
redis-cli -u redis://user:pass@host:6379/0 # URI format
redis-cli ping # PONG
redis-cli info memory
redis-cli --stat # Live stats (hits, misses, keys)
redis-cli --bigkeys # Find largest keys per type
redis-cli --memkeys # Sample memory usage per key
redis-cli --latency # Continuous latency measurement
redis-cli --scan --pattern "user:*" | head -20 # Safe key listing
redis-cli DBSIZE # Total key count
Strings
SET key "value"
GET key
SET session:abc "user123" EX 3600 # 1 hour TTL
SET key "val" PX 5000 # 5s in ms
SET key "val" EXAT 1700000000 # Unix timestamp expiry
SET lock:res "owner" NX EX 30 # Set if not exists (lock acquire)
SET key "val" XX # Update only if exists
INCR counter
INCRBY counter 5
DECR counter
INCRBYFLOAT price 2.50
MSET key1 "val1" key2 "val2"
MGET key1 key2
APPEND key " suffix"
STRLEN key
GETRANGE key 0 4 # Substring
Hashes
HSET user:1 name "Alice" email "alice@test.com" age 30
HGET user:1 name
HGETALL user:1
HMGET user:1 name email
HINCRBY user:1 age 1
HINCRBYFLOAT user:1 balance 9.99
HEXISTS user:1 email
HDEL user:1 age
HLEN user:1
HKEYS user:1
HSCAN user:1 0 MATCH "n*" COUNT 10 # Safe field iteration
Lists
LPUSH queue "task1" # Left (head)
RPUSH queue "task2" # Right (tail)
LPOP queue
RPOP queue
BLPOP queue 30 # Blocking pop (timeout 30s)
LRANGE queue 0 -1 # All elements
LLEN queue
LTRIM queue 0 99 # Keep first 100
LPOS queue "task1" # Find position
LMOVE src dst LEFT RIGHT # Atomic move between lists
Sets and Sorted Sets
# Sets
SADD tags "python" "redis" "docker"
SREM tags "docker"
SISMEMBER tags "python"
SMEMBERS tags
SCARD tags
SUNION tags1 tags2
SINTER tags1 tags2
SDIFF tags1 tags2
SRANDMEMBER tags 2
SPOP tags # Remove random member
SSCAN tags 0 MATCH "p*" COUNT 100
# Sorted sets
ZADD leaderboard 100 "alice" 95 "bob" 87 "charlie"
ZRANGE leaderboard 0 -1 WITHSCORES
ZREVRANGE leaderboard 0 2 WITHSCORES # Top 3
ZRANGEBYSCORE leaderboard 90 100
ZRANGEBYSCORE leaderboard -inf +inf LIMIT 0 10 # Paginate
ZRANK leaderboard "alice"
ZREVRANK leaderboard "alice"
ZINCRBY leaderboard 5 "bob"
ZCOUNT leaderboard 80 100
ZSCORE leaderboard "alice"
ZPOPMIN leaderboard # Pop lowest score
ZPOPMAX leaderboard # Pop highest score
ZUNIONSTORE dest 2 board1 board2 WEIGHTS 1 2
Streams, HyperLogLog, and Bitmaps
# Streams — append-only log for event sourcing / message queues
XADD events * action "click" page "/home" # Auto-generate ID
XLEN events
XRANGE events - + COUNT 10
XREAD COUNT 5 BLOCK 2000 STREAMS events $ # Blocking read
# Consumer groups (durable message queue)
XGROUP CREATE events mygroup $ MKSTREAM
XREADGROUP GROUP mygroup consumer1 COUNT 1 BLOCK 2000 STREAMS events >
XACK events mygroup <message-id>
XPENDING events mygroup # Check unacked messages
XCLAIM events mygroup consumer2 3600000 <id> # Claim stuck message
# HyperLogLog — cardinality estimation (~0.81% error, 12KB per key)
PFADD unique_visitors "user1" "user2" "user3"
PFCOUNT unique_visitors
PFMERGE total daily:mon daily:tue
# Bitmaps — bit-level operations on strings
SETBIT logins:2024-01-15 1001 1 # User 1001 logged in
GETBIT logins:2024-01-15 1001
BITCOUNT logins:2024-01-15 # Total logins that day
BITOP AND active_both logins:day1 logins:day2 # Users active both days
Key Management and TTL
SCAN 0 MATCH user:* COUNT 100 # Safe iteration (never KEYS in prod)
EXPIRE key 3600 # Set TTL (seconds)
PEXPIRE key 3600000 # Milliseconds
EXPIREAT key 1700000000 # Unix timestamp
TTL key # -1 = no expiry, -2 = missing
PERSIST key # Remove expiration
DEL key # Synchronous delete
UNLINK key # Async delete (non-blocking for large keys)
TYPE key
OBJECT ENCODING key # Internal encoding (ziplist, hashtable, etc.)
MEMORY USAGE key # Bytes consumed by key
EXISTS key key2 # Returns count of existing keys
RENAME key newkey
DUMP key # Serialize key
RESTORE newkey 0 <bytes> # Restore serialized key
Always set TTLs on cache keys. Jitter TTLs (add random seconds) to prevent thundering herd on mass expiry. Use EXPIREAT for calendar-aligned expirations.
Pub/Sub
SUBSCRIBE channel1 channel2
PSUBSCRIBE news.*
PUBLISH channel1 "Hello subscribers!"
PUBSUB CHANNELS # List active channels
PUBSUB NUMSUB channel1 # Subscriber count
Limitations: fire-and-forget (no persistence, no replay). Subscribers miss messages during disconnection. No acknowledgment. For durable messaging, use Streams with consumer groups.
Caching Patterns
# Cache-aside (lazy loading) — most common
GET cache:user:1
# Miss? Query DB, then: SET cache:user:1 '{"name":"Alice"}' EX 300
# Write-through — app writes cache + DB together on every write
SET cache:user:1 '{"name":"Alice"}' EX 300
# Write-behind — write cache immediately, async flush to DB
# Requires application-level queue to batch DB writes
# Cache stampede prevention — probabilistic early expiration
# Refresh when TTL < random threshold, or use background refresh with SET ... NX
Session Storage
HSET session:sid123 userId 1 role "admin" cart '["item1"]' lastAccess 1700000000
EXPIRE session:sid123 86400 # 24h TTL
HGET session:sid123 role
HSET session:sid123 lastAccess 1700000001
EXPIRE session:sid123 86400 # Refresh TTL on activity (sliding expiry)
Rate Limiting
# Fixed window (simple, but allows burst at window edges)
INCR ratelimit:user:1:1700000000
EXPIRE ratelimit:user:1:1700000000 60
# Reject if count > limit
# Sliding window log (accurate, higher memory)
ZADD ratelimit:user:1 <now_ms> <request_id>
ZREMRANGEBYSCORE ratelimit:user:1 0 <now_ms - window_ms>
ZCARD ratelimit:user:1
EXPIRE ratelimit:user:1 <window_seconds>
# Reject if count > limit
# Token bucket via Lua — see Lua scripting section
Distributed Lock (Redlock)
# Acquire
SET lock:resource <unique-id> NX EX 30
# Release atomically (Lua — only owner can release)
EVAL "if redis.call('GET',KEYS[1]) == ARGV[1] then return redis.call('DEL',KEYS[1]) else return 0 end" 1 lock:resource <unique-id>
# Multi-node Redlock: acquire on N/2+1 independent Redis nodes
# Use client libraries (redlock-py, redlock-node) for production
Transactions
# MULTI/EXEC — atomic batch execution
MULTI
SET user:1:balance 100
INCR stats:transactions
EXEC
# WATCH — optimistic locking (CAS)
WATCH user:1:balance
balance = GET user:1:balance
MULTI
SET user:1:balance <new-value>
EXEC # Returns nil if balance changed since WATCH
DISCARD # Abort queued transaction
Redis transactions are not rollback-capable. If a command fails inside EXEC, other commands still execute. Use Lua scripts for true atomic logic.
Lua Scripting
# Atomic operations on the server
EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 mykey "myval"
# Conditional update (compare-and-swap)
EVAL "
local cur = redis.call('GET', KEYS[1])
if cur == ARGV[1] then
redis.call('SET', KEYS[1], ARGV[2])
return 1
end
return 0
" 1 mykey "old" "new"
# Cache scripts (avoid resending text each call)
SCRIPT LOAD "return redis.call('GET', KEYS[1])"
# Returns SHA: "a42059b356c875f0717db19a51f6aaa9161571a2"
EVALSHA a42059b356c875f0717db19a51f6aaa9161571a2 1 mykey
SCRIPT EXISTS <sha>
# Token bucket rate limiter in Lua
EVAL "
local tokens = tonumber(redis.call('GET', KEYS[1]) or ARGV[1])
if tokens > 0 then
redis.call('SET', KEYS[1], tokens - 1, 'EX', ARGV[2])
return 1
end
return 0
" 1 bucket:user:1 "10" "60"
Persistence
# RDB snapshots (point-in-time, compact, fast restart)
CONFIG SET save "900 1 300 10 60 10000"
BGSAVE
# AOF (append-only file — durable, replayable log)
CONFIG SET appendonly yes
CONFIG SET appendfsync everysec # Options: always, everysec, no
BGREWRITEAOF # Compact AOF file
# Hybrid (Redis 7+) — RDB base + AOF for recent changes
CONFIG SET aof-use-rdb-preamble yes
RDB: faster restarts, smaller files, possible data loss between snapshots. AOF: more durable, larger files. Hybrid: recommended for production.
Redis Sentinel (High Availability)
redis-cli -p 26379 SENTINEL masters
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
redis-cli -p 26379 SENTINEL replicas mymaster
# sentinel.conf essentials:
# sentinel monitor mymaster 127.0.0.1 6379 2 # quorum = 2
# sentinel down-after-milliseconds mymaster 5000
# sentinel failover-timeout mymaster 60000
# sentinel auth-pass mymaster <password>
Sentinel monitors master and auto-promotes a replica on failure. Clients connect via Sentinel to discover the current master.
Redis Cluster (Sharding)
# 16384 hash slots distributed across nodes
redis-cli --cluster create host1:6379 host2:6379 host3:6379 \
--cluster-replicas 1 # 3 masters + 3 replicas
redis-cli --cluster info host1:6379
redis-cli --cluster check host1:6379
redis-cli --cluster reshard host1:6379 # Move hash slots
redis-cli -c -h host1 -p 6379 # -c follows MOVED redirects
# Hash tags — force keys to same slot
SET {user:1}:profile '...'
SET {user:1}:settings '...' # Same slot due to {user:1}
Multi-key commands (MGET, transactions) only work on keys in the same hash slot. Use hash tags {...} to colocate related keys.
Memory Optimization
CONFIG SET maxmemory 256mb
CONFIG SET maxmemory-policy allkeys-lru
# Eviction policies:
# noeviction — errors on write when full
# allkeys-lru — evict least recently used (general cache)
# allkeys-lfu — evict least frequently used
# volatile-lru — LRU among keys with TTL only
# volatile-ttl — evict keys with shortest TTL
# allkeys-random — random eviction
# Memory analysis
INFO memory # Used memory, fragmentation ratio
MEMORY DOCTOR # Automated memory advice
MEMORY USAGE key SAMPLES 5
redis-cli --bigkeys
Use hashes for small objects (ziplist encoding). Avoid large blobs — offload to object storage, cache references.
Connection Pooling
# Python (redis-py) — always use connection pools
import redis
pool = redis.ConnectionPool(host='localhost', port=6379, db=0,
max_connections=20, decode_responses=True)
r = redis.Redis(connection_pool=pool)
# Node.js (ioredis): pooling is built-in
Never create a new connection per request. Set max_connections based on concurrency. Use timeout and retry_on_timeout.
Monitoring
INFO all # Full server report
INFO stats # Hits, misses, ops/sec
INFO clients # Connected clients
INFO replication # Master/replica status
SLOWLOG GET 10 # Last 10 slow commands
CONFIG SET slowlog-log-slower-than 10000 # Log commands > 10ms
MONITOR # Stream all commands (debug only — perf hit)
CONFIG SET latency-monitor-threshold 100 # Track commands > 100ms
LATENCY LATEST
CLIENT LIST # All connected clients
CLIENT SETNAME "myapp-worker-1"
Common Patterns
# Leaderboard
ZADD leaderboard 100 "player:1"
ZINCRBY leaderboard 5 "player:1"
ZREVRANGE leaderboard 0 9 WITHSCORES # Top 10
# Geospatial
GEOADD locations -122.4194 37.7749 "san_francisco"
GEODIST locations "san_francisco" "new_york" km
GEOSEARCH locations FROMLONLAT -122.0 37.0 BYRADIUS 100 km ASC
# Recent activity feed (capped list)
LPUSH feed:user:1 '{"action":"post","id":42}'
LTRIM feed:user:1 0 99 # Keep last 100
# Idempotency check
SET idempotent:req:abc123 1 NX EX 86400 # nil if already processed
Reference
For caching patterns, pub/sub, and Lua scripts: references/patterns.md
More from 1mangesh1/dev-skills-collection
curl-http
HTTP request construction and API testing with curl and HTTPie. Use when user asks to "test API", "make HTTP request", "curl POST", "send request", "test endpoint", "debug API", "upload file", "check response time", "set auth header", "basic auth with curl", "send JSON", "test webhook", "check status code", "follow redirects", "rate limit testing", "measure API latency", "stress test endpoint", "mock API response", or any HTTP calls from the command line.
28database-indexing
Database indexing internals, index type selection, query plan analysis, and write-overhead tradeoffs across PostgreSQL, MySQL, and MongoDB. Use when user asks to "optimize queries", "create indexes", "fix slow queries", "read EXPLAIN output", "reduce query time", "index strategy", "database performance", "composite index", "covering index", "partial index", "index bloat", "unused indexes", or needs help diagnosing and resolving database performance problems.
13testing-strategies
Testing strategies, patterns, and methodologies across the full testing spectrum. Use when asked about unit tests, integration tests, e2e tests, test pyramid, mocking, test doubles, TDD, property-based testing, snapshot testing, test coverage, mutation testing, contract testing, performance testing, test data management, CI/CD testing, flaky tests, test anti-patterns, test organization, test isolation, test fixtures, test parameterization, or any testing strategy, approach, or methodology.
10secret-scanner
This skill should be used when the user asks to "scan for secrets", "find API keys", "detect credentials", "check for hardcoded passwords", "find leaked tokens", "scan for sensitive keys", "check git history for secrets", "audit repository for credentials", or mentions secret detection, credential scanning, API key exposure, token leakage, password detection, or security key auditing.
10terraform
Terraform infrastructure as code for provisioning, modules, state management, and workspaces. Use when user asks to "create infrastructure", "write Terraform", "manage state", "create module", "import resource", "plan changes", or any IaC tasks.
10kubernetes
Kubernetes and kubectl mastery for deployments, services, pods, debugging, and cluster management. Use when user asks to "deploy to k8s", "create deployment", "debug pod", "kubectl commands", "scale service", "check pod logs", "create ingress", or any Kubernetes tasks.
10