## Intro

This guide covers the Redis commands that operators and developers reach for every day: setting keys with expirations, atomic counters, hashes for object data, lists for queues, sets for membership, sorted sets for rankings, safe iteration with SCAN, optimistic transactions, pub/sub messaging, and essential health checks. Every example uses the app:test:* namespace so you can run them against a real instance without touching production data.

## Workflow Overview

Follow this sequence for reliable, repeatable results:

- Connect and sanity check — PING and INFO confirm reachability and baseline metrics.

- Strings and expirations — SET / GET with EX / TTL for cache-like data.

- Counters — INCR / DECR with TTL for rate limits and metrics.

- Collections — HASH , LIST , SET , ZSET commands for structured data.

- Safe iteration — SCAN instead of KEYS to avoid blocking.

- Transactions — WATCH , MULTI , EXEC for compare-and-swap updates.

- Pub/Sub — quick fan-out messaging for ephemeral events.

- Observability — INFO , MEMORY , SLOWLOG for health and tuning.

## Keys and Strings

### Connect and ping

redis-cli PING 
 Expected output: PONG

### Set with expiration and get

redis-cli SET app:test:greeting "hello" EX 60 NX
redis-cli GET app:test:greeting
redis-cli TTL app:test:greeting 
 Notes:

- EX sets seconds-to-live. NX avoids overwriting existing keys; use XX to require existence.

- Namespaces like app:test:* isolate samples from real data.

### Update value and check existence

redis-cli SET app:test:greeting "hello, world" XX
redis-cli EXISTS app:test:greeting 

### Get and change TTL in one step

 redis-cli GETEX app:test:greeting EX 120
redis-cli TTL app:test:greeting 

### Remove expiration if needed

 redis-cli PERSIST app:test:greeting 

### Delete carefully (target test namespaces only)

 redis-cli DEL app:test:greeting 

### Multi-key operations

 redis-cli MSET app:test:a 1 app:test:b 2
redis-cli MGET app:test:a app:test:b 

## Counters and Rate Limits

### Initialize with TTL, then increment atomically

 redis-cli SET app:test:login:count 0 EX 3600 NX
redis-cli INCR app:test:login:count
redis-cli INCRBY app:test:login:count 5
redis-cli TTL app:test:login:count 
 Pattern: Ensure the TTL persists for counters by setting it when the key is first created ( SET ... NX EX ). For sliding windows, use INCR with separate timestamped keys per window bucket (e.g., ratelimit:u123:2024011514 for 14:00 UTC).

### Simple rate limit check (fixed 60-second window)

redis-cli INCR app:test:ratelimit:u123
redis-cli TTL app:test:ratelimit:u123 
 If TTL returns -2 (key has no expiry), apply it now for a 60-second window:

redis-cli EXPIRE app:test:ratelimit:u123 60 
 Then check the count against your limit (e.g., 10 requests/minute):

redis-cli GET app:test:ratelimit:u123 

## Hashes

 Hashes store object-like fields efficiently — ideal for user profiles, session data, or product records.

redis-cli HSET app:test:user:1001 name "Ada" plan "pro" visits 1
redis-cli HGET app:test:user:1001 name
redis-cli HMGET app:test:user:1001 name plan visits
redis-cli HINCRBY app:test:user:1001 visits 1 
 Caution: HGETALL can be heavy on very large hashes (thousands of fields). Prefer HMGET for specific fields when possible.

## Lists

Lists work well for queues and ordered logs. Use small payloads (IDs) and fetch full data from a hash or database.

### FIFO queue with LPUSH + RPOP

redis-cli DEL app:test:queue:emails
redis-cli LPUSH app:test:queue:emails id-1 id-2 id-3
redis-cli RPOP app:test:queue:emails
redis-cli RPOP app:test:queue:emails 

### Blocking pop (waits for an item, 5-second timeout)

 redis-cli BRPOP app:test:queue:emails 5 
 Output format: 1) "app:test:queue:emails" 2) "id-3"

## Sets and Sorted Sets

### Sets — unique items, ideal for membership and de-dup

redis-cli SADD app:test:room:active u1 u2 u2 u3
redis-cli SISMEMBER app:test:room:active u2
redis-cli SMEMBERS app:test:room:active
redis-cli SREM app:test:room:active u1 

### Sorted sets — rank items by score

 redis-cli ZADD app:test:scores 100 u1 250 u2 180 u3
redis-cli ZRANGE app:test:scores 0 -1 WITHSCORES
redis-cli ZREVRANGE app:test:scores 0 1 WITHSCORES
redis-cli ZINCRBY app:test:scores 25 u1 
 Use case: leaderboards, priority queues, time-series ordering.

## Finding Data Safely

Avoid KEYS in production — it blocks the server on large datasets. Prefer SCAN , which is incremental and non-blocking.

### Basic SCAN pattern

redis-cli SCAN 0 MATCH app:test:* COUNT 100 
 Output: cursor followed by matching keys. Loop until the cursor returns 0 to finish scanning.

# Cursor 0 -> first batch
redis-cli SCAN 0 MATCH app:test:* COUNT 100
# Returns: 1) "17" 2) 1) "app:test:a" 2) "app:test:b" ...

# Cursor 17 -> next batch
redis-cli SCAN 17 MATCH app:test:* COUNT 100
# Returns: 1) "0" 2) 1) "app:test:user:1001" ... 

### Collection-specific variants

- HSCAN key cursor [MATCH pattern] [COUNT n]

- SSCAN key cursor [MATCH pattern] [COUNT n]

- ZSCAN key cursor [MATCH pattern] [COUNT n]

## Transactions

 Use WATCH + MULTI + EXEC for optimistic locking. If another client modifies a watched key, EXEC returns nil — retry the whole flow.

### Example: transfer credits if balance is sufficient

# Seed demo data
redis-cli SET app:test:balance:u1 100
redis-cli SET app:test:balance:u2 50

# Start a guarded update: debit 30 from u1, credit 30 to u2
redis-cli WATCH app:test:balance:u1
redis-cli GET app:test:balance:u1
# Returns "100" — proceed
redis-cli MULTI
redis-cli DECRBY app:test:balance:u1 30
redis-cli INCRBY app:test:balance:u2 30
redis-cli EXEC 
 If EXEC returns (nil) , another client changed balance:u1 — re-read and retry.

## Pub/Sub Basics

Publish/subscribe is for ephemeral messages (not stored). Late subscribers miss past messages.

### Terminal A (subscriber)

redis-cli SUBSCRIBE app:test:events 
 Output:

1) "subscribe"
2) "app:test:events"
3) (integer) 1 

### Terminal B (publisher)

 redis-cli PUBLISH app:test:events "hello subscribers" 
 Returns (integer) 1 — number of clients that received the message.

### Terminal A receives

1) "message"
2) "app:test:events"
3) "hello subscribers" 

## Observability and Health

### Quick checks

- PING — confirms reachability.

- INFO — server, memory, clients, keyspace stats.

 redis-cli INFO memory | head -n 10 

### Memory usage of a specific key

 redis-cli MEMORY USAGE app:test:user:1001 
 Returns bytes (e.g., 112 ). Use MEMORY USAGE key SAMPLES 5 for large collections.

### Find slow commands

redis-cli SLOWLOG GET 10 
 Output fields: unique ID, unix timestamp, duration in microseconds, command + args. Investigate anything over your latency budget (e.g., >10ms).

### Live traffic debugging

MONITOR streams every command — use carefully and briefly.

redis-cli MONITOR 
 Press Ctrl-C to quit. Warning: on busy instances, MONITOR output volume can affect performance.

## Local Pilot Plan

Keep the first rollout narrow, measurable, and easy to inspect.

### Scope

- Namespace all test keys under app:test:* .

- Exercise only these commands: SET / GET / EXPIRE / TTL , INCR , HSET / HGET , LPUSH / RPOP , SADD / SISMEMBER , ZADD / ZRANGE , SCAN , INFO .

### Steps

- Sanity check: PING and INFO memory ; record baseline used_memory and keyspace stats.

- Run the examples in this guide exactly as written.

- Verify outcomes: MGET values, TTL s, SCAN counts, and MEMORY USAGE on a few keys.

- Clean up: DEL only keys under app:test:* .

- Compare before/after INFO keyspace and memory to ensure no strays.

### Success criteria

- All commands return expected values.

- No lingering keys after cleanup ( SCAN app:test:* returns none).

- No slowlog entries introduced by the pilot.

## Conclusion

You now have a practical toolkit for daily Redis operations: safe key creation with expirations, atomic counters, object-like hashes, queues with lists, unique and ranked collections with sets and sorted sets, non-blocking iteration via SCAN , simple optimistic transactions, pub/sub for ephemeral events, and essential health checks via INFO , MEMORY , and SLOWLOG . Keep examples namespaced, favor SCAN over KEYS , and monitor INFO , MEMORY , and SLOWLOG during experiments. Start with the local pilot, confirm results, then expand to your application-specific keys and patterns.