Redis Tutorials: A Complete Fundamental Turorials

From Fundamentals to Production-Grade Caching, Sessions, Pub/Sub, Counters, Locks and Failure Handling


1. What is Redis?

Redis is a high-performance, primarily in-memory data store.

The easiest mental model is:

Redis is a shared, extremely fast data-structure server that applications access over the network.

Instead of limiting you to simple key → value pairs, Redis lets the value associated with a key be a String, Hash, List, Set, Sorted Set, Stream, and several other specialized structures. Redis officially describes itself as an in-memory data store that can be used for caching, messaging, streaming, document/vector workloads and other use cases, with replication and optional disk persistence.

A simple application might look like this:

flowchart LR
    U[User] --> A[Application]
    A --> R[(Redis)]
    A --> D[(Database)]

    R -->|Fast cached data| A
    D -->|Source of truth| A

Without Redis:

Application
     |
     | SQL query
     v
 Database
     |
     | 20-200 ms
     v
 Application

With Redis:

Application
     |
     | GET product:100
     v
   Redis
     |
     | Often sub-millisecond / low-millisecond
     v
 Application

The exact latency depends on network, deployment, workload and payload size, but the important idea is:

memory access is normally much faster than repeatedly performing expensive database queries or external API calls.


2. Why Does Redis Exist?

Imagine an e-commerce site.

Thousands of customers repeatedly request:

Product ID: 100
Name: MacBook Pro
Price: ₹180000
Category: Laptop
Availability: In Stock

Without caching:

Customer 1 ──→ Database
Customer 2 ──→ Database
Customer 3 ──→ Database
Customer 4 ──→ Database
Customer 5 ──→ Database

The database repeatedly performs essentially the same work.

With Redis:

                 ┌──────────────┐
Customer ───────>│ Application  │
                 └──────┬───────┘
                        |
                    Check Redis
                        |
              ┌─────────▼─────────┐
              │       Redis       │
              │ product:100       │
              └─────────┬─────────┘
                        |
                   Cache HIT
                        |
                        v
                     Return

Only when Redis does not have the data does the application normally query the database.


3. Redis Is Not Just a Cache

This is one of the most important Redis concepts.

Redis can be used for:

RequirementRedis capability
Application cachingStrings / Hashes
User sessionsStrings / Hashes + TTL
CountersINCR, INCRBY
LeaderboardsSorted Sets
Unique membershipSets
QueuesLists / Streams
Live notificationsPub/Sub
Event processingStreams
Rate limitingCounters + expiration
Temporary distributed coordinationSET NX
Geospatial lookupGeospatial indexes
Unique visitor estimationHyperLogLog

Redis’ current documentation describes Redis as a data structure server, with native structures intended for use cases ranging from caching and queuing to event processing.


4. Redis Architecture — Simple Mental Model

Redis normally sits between your application and slower systems.

flowchart TB

    USER[Users]

    LB[Load Balancer]

    A1[Application Instance 1]
    A2[Application Instance 2]
    A3[Application Instance 3]

    R[(Redis)]

    DB[(Primary Database)]

    USER --> LB

    LB --> A1
    LB --> A2
    LB --> A3

    A1 --> R
    A2 --> R
    A3 --> R

    A1 --> DB
    A2 --> DB
    A3 --> DB

Redis provides something extremely useful here:

shared fast state.

Application instances do not need to keep everything inside their own memory.

For example:

App-1 local memory ≠ App-2 local memory

But:

App-1 ──┐
App-2 ──┼──> Same Redis
App-3 ──┘

All application instances can access the same session, counter, cached object or temporary lock.


5. Running Redis Locally

For learning, Docker is one of the easiest approaches. Redis’ official documentation provides Docker as one of its supported installation/run options.

Start Redis:

docker run --name redis-lab \
  -p 6379:6379 \
  -d redis

Check the container:

docker ps

Open Redis CLI:

docker exec -it redis-lab redis-cli

Test Redis:

PING

Result:

PONG

Your Redis environment is ready.


6. Your First Redis Commands

Store something:

SET name "Rajesh"

Read it:

GET name

Result:

"Rajesh"

Delete it:

DEL name

Check whether it exists:

EXISTS name

Expiration:

SET verification_code "928431" EX 300

This means:

Key   = verification_code
Value = 928431
TTL   = 300 seconds

Check remaining TTL:

TTL verification_code

Redis supports expiration directly as part of SET as well as through expiration commands such as EXPIRE.


7. Keys Are Extremely Important

Redis applications commonly use readable hierarchical key names.

Instead of:

123

prefer:

user:123

For a session:

session:a81fc92

For a product:

product:1001

For a shopping cart:

cart:user:100

For a rate limiter:

rate:user:100:2026-08-19T07:33

For a temporary lock:

lock:order:5432

A useful convention is:

<domain>:<entity>:<id>

For example:

ecommerce:product:1001
ecommerce:user:700
ecommerce:session:abc123

Good key naming dramatically improves debugging and operations.


8. Redis Data Structures

Redis’ most important characteristic is that values are not all treated as identical blobs.

The core structures you should understand first are:

StructureThink of it asCommon use case
StringSingle valueCache, token, counter
HashObject / recordUser, product, session
ListOrdered sequenceQueue
SetUnique collectionTags, membership
Sorted SetRanked collectionLeaderboard
StreamAppend-only event logEvent processing
BitmapBitsDaily activity flags
HyperLogLogApproximate unique countUnique visitors

Redis currently supports an even broader collection of native and specialized data types, but mastering these core structures gives you the foundation for most application workloads.


9. Redis String

A Redis String is the simplest structure.

key → value

Example:

SET product:100:name "iPhone"
GET product:100:name

Strings are ideal for:

  • cached JSON
  • tokens
  • OTPs
  • feature flags
  • configuration
  • counters

Example JSON:

SET product:100 '{"name":"iPhone","price":80000}'

Retrieve:

GET product:100

Output:

{"name":"iPhone","price":80000}

When should you use String?

Use String when:

One key represents one logical value.

For example:

user:100:last_login → "2026-08-19"

10. Redis Hash

A Hash represents an object containing fields.

Think:

user:100
   |
   +-- name  = Asha
   +-- city  = Delhi
   +-- age   = 30

Commands:

HSET user:100 name "Asha" city "Delhi" age 30

Read one field:

HGET user:100 name

Read everything:

HGETALL user:100

Update one field:

HSET user:100 city "Mumbai"

A Redis Hash naturally represents many application records because Redis hashes are field-value collections similar to dictionaries or maps in programming languages.

Appropriate use cases

User profile
Shopping cart
Session information
Product metadata
Application configuration

11. Redis List

A List is an ordered sequence.

Task A
Task B
Task C
Task D

Add:

LPUSH jobs "send-email"

Add another:

LPUSH jobs "generate-report"

Read:

LRANGE jobs 0 -1

Redis lists preserve insertion ordering.

They can be useful for simple queue-like workloads.

However:

For sophisticated durable event processing, retries, consumer groups and replay, consider Redis Streams or a dedicated messaging platform rather than treating a List as a complete messaging system.


12. Redis Set

A Set contains unique values.

SADD product:100:tags electronics
SADD product:100:tags mobile
SADD product:100:tags apple

Get members:

SMEMBERS product:100:tags

Adding apple again:

SADD product:100:tags apple

does not create a duplicate.

Think:

Set = unique unordered collection

Typical use cases:

User roles
Permissions
Unique tags
Online users
Group membership
Unique categories

Redis sets support constant-time add, remove and membership checks in typical cases.


13. Redis Sorted Set

A Sorted Set contains unique members, but every member has a score.

Example leaderboard:

ZADD leaderboard 500 Alice
ZADD leaderboard 900 Bob
ZADD leaderboard 700 Charlie

Read ranking:

ZRANGE leaderboard 0 -1 WITHSCORES

Conceptually:

Bob       900
Charlie   700
Alice     500

Use Sorted Sets for:

Leaderboards
Priority systems
Ranking
Scores
Scheduling
Top-N queries

The difference is:

SET
Unique values

SORTED SET
Unique values + score + ordering

Redis defines sorted sets as unique strings maintained in order according to their associated score.


14. Redis Streams

A Stream is fundamentally different.

Think:

Event 1
Event 2
Event 3
Event 4
        ↓
new events keep arriving

Example:

XADD orders * order_id 1001 status created

Another:

XADD orders * order_id 1002 status created

Read:

XRANGE orders - +

Redis describes Streams as an append-only log designed to record events in sequence and make them available for processing.

Good use cases include:

Order events
Audit events
Telemetry
Background processing
Consumer groups
Durable event workflows

15. Data Structure Decision Guide

A very practical way to remember Redis structures is:

Need one value?
        |
      String

Need object fields?
        |
       Hash

Need ordered queue?
        |
       List

Need unique values?
        |
       Set

Need ranking?
        |
    Sorted Set

Need durable event log?
        |
      Stream

Or:

RequirementChoose
Cache product JSONString
Store session fieldsHash
Simple task queueList
Unique usersSet
LeaderboardSorted Set
Durable event processingStream

16. What Is Caching?

Caching means:

Store expensive-to-obtain data somewhere faster so the next request does not have to perform the expensive operation again.

Suppose:

Database query = 80 ms
Redis GET      = much faster

Instead of hitting the database 10,000 times for the same product:

Database
Database
Database
Database
Database

we cache it:

             Redis
           / / | \ \
        request request
             |
        Database only
        when necessary

17. Cache Hit and Cache Miss

These two terms are fundamental.

Cache HIT

Application asks Redis:

GET product:100

Redis has it.

Application
     |
     v
   Redis
     |
    HIT
     |
     v
  Response

No database query is needed.


Cache MISS

Redis does not have it.

Application
     |
     v
   Redis
     |
    MISS
     |
     v
 Database

The application fetches the data and normally stores it in Redis.


18. Cache-Aside Pattern

Cache-aside is probably the most important Redis caching pattern to learn.

It is also called:

Lazy Loading

The application manages the cache.

The process is:

flowchart TD

    A[Application receives request]

    B{Data in Redis?}

    C[Return cached data]

    D[Query Database]

    E[Store result in Redis]

    F[Return result]

    A --> B

    B -->|Yes - HIT| C
    B -->|No - MISS| D

    D --> E
    E --> F

Algorithm:

1. Check Redis.
2. If found → return it.
3. If not found → query database.
4. Put database result into Redis.
5. Return result.

19. Cache-Aside Example

Assume:

GET /products/100

Pseudo-code:

def get_product(product_id):

    key = f"product:{product_id}"

    # Step 1: Check Redis
    cached = redis.get(key)

    if cached:
        return cached

    # Step 2: Cache miss
    product = database.find_product(product_id)

    # Step 3: Put data into Redis
    redis.set(key, product, ex=300)

    # Step 4: Return result
    return product

The first request looks like:

Client
  |
  v
Application
  |
  | GET product:100
  v
Redis
  |
 MISS
  |
  v
Database
  |
 Product
  |
  v
Redis SET + TTL
  |
  v
Client

Second request:

Client
  |
  v
Application
  |
  v
Redis
  |
 HIT
  |
  v
Client

No database access.


20. Why Cache-Aside Is So Popular

It has several attractive properties.

The database remains the source of truth.

Redis contains copies of frequently accessed data.

If Redis loses a cache entry:

Not catastrophic

because the application can recreate it from the database.

This architecture is extremely common:

Redis = optimization
Database = authority

That distinction is one of the safest Redis design principles.


21. The Problem With Cache-Aside

Caching introduces another copy of the data.

Suppose:

Database:

product:100.price = ₹80,000

Redis:

product:100.price = ₹80,000

Someone updates the database:

product:100.price = ₹75,000

But Redis still contains:

₹80,000

You now have:

Stale Data

That leads directly to one of the hardest caching problems:

Cache Invalidation


22. Read-Through / Cache-Through

In cache-aside:

Application knows how to load the cache.

Conceptually:

Application
   |
   +---- Redis
   |
   +---- Database

In a read-through/cache-through abstraction, the application interacts with a cache layer:

Application
     |
     v
Cache Layer
     |
     +---- Redis
     |
     +---- Database loader

When data is missing:

Cache Layer
     |
     v
Database
     |
     v
Redis

The difference is primarily who owns the loading logic.

Redis commands themselves do not magically execute your SQL query because GET misses. A framework, library or application layer implements that behavior.


23. Write-Through Caching

Write-through means:

When the application writes data, the authoritative store and cache are updated as part of the write path.

Conceptually:

flowchart LR

    A[Application]
    C[Cache Layer]
    R[(Redis)]
    D[(Database)]

    A -->|Write| C
    C --> D
    C --> R

Example:

UPDATE product price
        |
        +----> Database = ₹75,000
        |
        +----> Redis    = ₹75,000

The goal is to keep Redis warm and synchronized.


24. Write-Behind / Write-Back

Another architecture sometimes discussed alongside these patterns is write-behind.

Application
     |
     v
   Cache
     |
     | asynchronous
     v
 Database

The application may return before the database has been updated.

Advantage:

Very fast writes

Risk:

Cache failure before persistence
      ↓
Potential data loss

This pattern requires much more careful durability design.

For ordinary application caching, cache-aside or well-designed write-through strategies are usually easier to reason about.


25. Cache Pattern Comparison

PatternRead miss handled byWrites handled byComplexityTypical use
Cache-asideApplicationApplication/DBLowMost applications
Read-throughCache abstractionApplicationMediumFramework-managed caching
Write-throughCache abstractionCache + DBMediumFrequently read data
Write-behindCache layerEventually DBHighSpecialized high-write workloads

The easiest pattern for most developers to start with is:

Cache-Aside


26. TTL — Time To Live

TTL determines how long a cached value remains valid.

Example:

SET product:100 "..." EX 300

means:

Store this key for 300 seconds.

After that:

Redis removes/expires it.

Check:

TTL product:100

27. Why TTL Is Important

Without TTL:

Old cache entries
      +
Unused cache entries
      +
Potentially stale values
      =
Memory and correctness problems

TTL provides a safety mechanism.

But:

TTL is not a replacement for proper invalidation when freshness matters.


28. How Should You Select TTL?

This question does not have one universal answer.

Do not think:

Redis TTL should always be 5 minutes.

Instead ask:

How stale is this data allowed to become?

Examples:

DataPossible TTL
Country listHours / days
Product descriptionMinutes / hours
Product priceShorter
InventorySeconds or event-invalidated
User profileMinutes
OTP1–10 minutes
SessionBased on session policy
Static configurationLong
Real-time balanceOften avoid ordinary stale caching

The correct TTL comes primarily from the application’s freshness requirement, not from a Redis rule.


29. TTL Decision Model

Consider four things:

Business freshness requirement
          +
How frequently data changes
          +
Cost of rebuilding cache
          +
Traffic / database capacity
          =
TTL decision

For example:

Product Description
changes once per week
↓
TTL could be relatively long

But:

Flash Sale Price
changes frequently
↓
Long TTL could be dangerous

30. TTL Jitter

Imagine 100,000 product keys are populated at 10:00 AM with:

TTL = exactly 3600 seconds

At 11:00 AM:

100,000 keys expire

Suddenly:

100,000 requests → database

This can cause a cache stampede.

Instead of identical TTLs:

3600
3600
3600
3600
3600

use jitter:

3412
3678
3554
3721
3498

For example:

ttl = 3600 + random.randint(-300, 300)

Now expiration is distributed across time.


31. Absolute vs Sliding Expiration

Absolute expiration

Session:

Created 09:00
Expires 10:00

Usage does not extend it.


Sliding expiration

Every valid activity refreshes expiration.

09:00 login
      |
09:20 activity → expiry becomes 10:20
      |
09:50 activity → expiry becomes 10:50

Sliding expiration is common for user sessions.

However, security-sensitive applications may combine:

Idle timeout
+
Maximum absolute lifetime

so a session cannot live forever.


32. Cache Invalidation

Cache invalidation means:

Removing or replacing cached data when the underlying authoritative data changes.

Example:

Database
product:100
price = ₹80,000

Redis
product:100
price = ₹80,000

Price changes:

Database = ₹75,000

What should happen to Redis?

You need an invalidation strategy.


33. Strategy 1 — TTL-Only Invalidation

Update DB:

Database = ₹75,000

Do nothing to Redis.

Wait until:

TTL expires

Simple but potentially stale.

Use when:

Temporary staleness is acceptable.

34. Strategy 2 — Delete Cache After Database Update

One of the most common strategies is:

1. Update Database
2. Delete Redis key

Example:

database.update_product(product)

redis.delete(f"product:{product.id}")

Next request:

Redis MISS
    |
    v
Database
    |
    v
Fresh data
    |
    v
Redis

This is often safer than trying to independently reconstruct the exact cached representation during every write.


35. Strategy 3 — Update the Cache

Another option:

UPDATE database
UPDATE Redis

Example:

database.update_product(product)

redis.set(
    f"product:{product.id}",
    serialize(product),
    ex=300
)

Advantage:

Cache remains warm.

But application logic becomes more complicated because every write path must correctly update every relevant cache key.


36. Strategy 4 — Event-Driven Invalidation

Large systems often use events.

Example:

Product Service
      |
      | ProductUpdated
      v
Message Broker
      |
      v
Cache Invalidation Worker
      |
      v
Redis DEL product:100

This helps when many systems maintain derived caches.


37. Cache Invalidation Golden Rule

Think of cached data as:

A derived copy

not:

Automatically synchronized truth

The system must answer:

Who updates the authoritative data?

Who invalidates the cache?

What happens if invalidation fails?

How stale may the cache become?

TTL should frequently remain as a backup safety mechanism even if you actively invalidate keys.


38. Cache Stampede

Now consider this very common failure.

A popular key:

homepage:recommendations

receives:

20,000 requests/second

Redis contains it.

Everything works:

20,000 requests
       |
       v
     Redis

Then the key expires.

All requests see:

CACHE MISS

And all query the database.

flowchart TD

    K[Popular Redis key expires]

    A1[Request 1]
    A2[Request 2]
    A3[Request 3]
    A4[Request 10,000]

    DB[(Database)]

    K --> A1
    K --> A2
    K --> A3
    K --> A4

    A1 --> DB
    A2 --> DB
    A3 --> DB
    A4 --> DB

This is:

Cache Stampede

also called:

Thundering Herd
Dogpile Effect

39. Why Cache Stampede Is Dangerous

Normally:

Redis protects database.

During a stampede:

Redis key expires
        ↓
Huge number of cache misses
        ↓
Huge database traffic
        ↓
Database slows down
        ↓
Requests take longer
        ↓
Even more requests accumulate
        ↓
Possible outage

A cache that was intended to protect the database can therefore contribute to a sudden load spike if expiration is not designed carefully.


40. Stampede Protection — TTL Jitter

First technique:

Do not expire thousands of related keys simultaneously.

Instead:

baseTTL + random jitter

Example:

ttl = 300 + random.randint(0, 60)

41. Stampede Protection — Single Refresher

Instead of allowing every request to rebuild the cache:

Request A → obtains refresh lock
Request B → waits / serves stale
Request C → waits / serves stale
Request D → waits / serves stale

Only:

Request A → Database

Once refreshed:

Redis populated

and other requests use the new value.


42. Stale-While-Revalidate

Another powerful pattern:

Cache value exists
but soft TTL expired

Instead of blocking the customer:

Return slightly stale value
        +
Refresh cache in background

Conceptually:

                    ┌──> Return stale value
Request → Redis ────┤
                    └──> One worker refreshes
                              |
                              v
                           Database

This can be excellent for:

Homepages
Recommendations
Content
Catalog information

It may be unacceptable for:

Account balances
Critical inventory guarantees
Security permissions

The business meaning of stale data matters.


43. Stale Data Risk

Caching always creates the possibility of:

Database value ≠ cached value

Example:

Database inventory = 0

Redis inventory = 5

If Redis is blindly trusted:

Customer may purchase nonexistent stock.

Therefore ask:

Is the data informational, or is it authoritative for a critical decision?

For critical decisions:

Redis can accelerate the process

but the authoritative transactional system may still need to validate the final action.


44. Redis Pub/Sub

Pub/Sub stands for:

Publish / Subscribe

Components:

Publisher
Channel
Subscriber

Example:

flowchart LR

    P[Order Service]

    C((order-events))

    S1[Email Service]
    S2[Notification Service]
    S3[WebSocket Service]

    P -->|Publish| C

    C --> S1
    C --> S2
    C --> S3

Redis uses commands such as:

SUBSCRIBE
PUBLISH
UNSUBSCRIBE

for this model.


45. Redis Pub/Sub Example

Terminal 1:

SUBSCRIBE orders

Terminal 2:

PUBLISH orders "order-1001-created"

Subscriber receives the message.

Another example:

PUBLISH notifications "user-100-logged-in"

46. Pub/Sub Is Not a Durable Queue

This is critical.

Redis Pub/Sub provides at-most-once delivery.

If a subscriber is disconnected when the message is published:

Message can be lost permanently.

Redis explicitly documents this behavior and recommends Streams when stronger delivery guarantees and persistence are required.

Think:

Pub/Sub

"Who is listening RIGHT NOW?"

versus:

Stream

"Record this event so consumers can process it."

47. Pub/Sub vs Redis Streams

FeaturePub/SubStreams
Persistent messagesNoYes
Offline consumer receives old messageNoPossible
Consumer groupsNoYes
ReplayNoYes
Simple live broadcastExcellentPossible
Durable processingPoor fitGood fit

Use Pub/Sub for:

Live notifications
WebSocket fan-out
Live dashboards
Cache invalidation notification
Ephemeral events

Use Streams when:

Events must not simply disappear because a consumer disconnected.

48. Redis Pub/Sub vs Kafka

They solve overlapping but different problems.

Redis Pub/Sub
       ↓
Fast ephemeral broadcast
Kafka
       ↓
Durable distributed event log

A useful simplified comparison:

RequirementRedis Pub/SubKafka
Live broadcastExcellentYes
Durable event logNoYes
ReplayNoYes
Long retentionNoYes
Consumer offsetsNoYes
Very simple notificationsExcellentOften overkill
Enterprise event backboneUsually noStrong fit

Do not automatically replace Kafka with Redis Pub/Sub simply because both can transmit messages.


49. Redis for User Sessions

Sessions are one of Redis’ classic use cases.

Imagine three application instances:

flowchart TB

    U[User]

    LB[Load Balancer]

    A1[App 1]
    A2[App 2]
    A3[App 3]

    R[(Redis Session Store)]

    U --> LB

    LB --> A1
    LB --> A2
    LB --> A3

    A1 --> R
    A2 --> R
    A3 --> R

Without shared session storage:

User logs in through App-1.

Next request goes to App-2.

App-2:
"Who are you?"

With Redis:

App-1
App-2
App-3
   |
   v
Same Redis session

Any application instance can resolve the session.


50. Session Example

Key:

session:f81d4fae

Hash:

HSET session:f81d4fae \
    user_id 100 \
    role admin \
    authenticated true

Expiration:

EXPIRE session:f81d4fae 1800

Meaning:

Session expires after 30 minutes

On logout:

DEL session:f81d4fae

51. Session Design Recommendations

A session should normally have an expiration policy.

Avoid:

session:* with no expiration forever

Also avoid placing unnecessary sensitive information directly into session objects.

Prefer:

Session ID
User ID
Authorization/context information needed for session
Timestamps
Minimal metadata

Keep the authoritative user/account records elsewhere unless Redis has deliberately been designed as their primary system.


52. Distributed Counters

Imagine ten application servers.

All must increment:

Number of API requests

Local counters do not work:

App-1 = 100
App-2 = 200
App-3 = 170

Redis provides shared counters:

            Redis
              |
       api_requests = 470
        /     |      \
      App1   App2    App3

53. INCR

Initialize:

SET pageviews 0

Increment:

INCR pageviews

Again:

INCR pageviews

Result:

2

Add 10:

INCRBY pageviews 10

Result:

12

Redis performs these counter operations atomically, which makes them extremely useful when many application instances modify the same counter.


54. Counter Use Cases

Counters work well for:

Page views
API calls
Downloads
Login attempts
Rate limiting
Usage quotas
Votes
Temporary metrics

Example:

INCR article:500:views

Ten application instances can safely increment the same Redis key.


55. Simple Rate Limiting

Suppose:

Maximum = 100 requests/minute/user

Key:

rate:user:100:202608190733

First request:

SET rate:user:100:202608190733 1 EX 60 NX

Subsequent requests:

INCR rate:user:100:202608190733

If counter becomes:

101

reject the request.

Concept:

Request
   |
   v
INCR counter
   |
   +-- <= 100 → Allow
   |
   +-- > 100  → Reject

Production-grade rate limiting may use Lua scripts, sorted sets or other algorithms such as sliding windows or token buckets depending on fairness and precision requirements.


56. Lightweight Distributed Locks

Suppose two workers attempt:

Generate invoice 1001

at the same time.

Without coordination:

Worker A ──> Generate
Worker B ──> Generate

Possible duplicate invoice

A Redis lock can coordinate temporary access.


57. Basic Redis Lock

Use:

SET lock:invoice:1001 abc123 NX EX 10

Meaning:

SET     = create key
NX      = only if key does not already exist
EX 10   = automatically expire after 10 seconds
abc123  = unique owner token

Redis’ SET command supports conditional creation with NX and expiration with EX/PX.

If successful:

Worker owns lock.

If it fails:

Someone else owns lock.

58. Why Lock Expiration Is Essential

Never create:

SET lock:invoice:1001 locked NX

without thinking about failure.

Suppose:

Worker obtains lock
      |
      v
Worker crashes

Lock remains forever.

Now:

Nobody can process invoice 1001.

Expiration creates a lease:

Lock eventually disappears.

59. Do Not Blindly Delete Somebody Else’s Lock

Consider:

Worker A obtains lock for 10 sec.

Worker A becomes slow.

Lock expires.

Worker B obtains new lock.

Worker A wakes up.

Worker A executes DEL lock.

Worker A has accidentally deleted:

Worker B's lock.

That is why the value should contain a unique ownership token.

Example:

lock:invoice:1001
         |
         v
550e8400-e29b-41d4-a716

The owner should release the lock only if the stored token still belongs to it.

A classic safe release is an atomic compare-and-delete operation, often implemented with a small Lua script.

if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
else
    return 0
end

60. What Redis Locks Are Good For

Good examples:

Prevent duplicate background refresh
Coordinate cache rebuild
Prevent duplicate scheduled job
Short-lived idempotency coordination
Temporary singleton work

Be more cautious with:

Bank transfer correctness
Financial settlement
Strict leader election
Irreversible infrastructure control
Safety-critical coordination

A Redis lock is useful, but it is not automatically a substitute for a consensus system or database transaction.

For strict correctness, consider:

Database constraints
Transactions
Idempotency keys
Fencing tokens
Consensus-based coordination

depending on the problem.


61. Connection Pooling

Applications should not normally do this for every request:

Request
   |
Create TCP connection
   |
Authenticate
   |
Execute GET
   |
Close connection

Then repeat:

10,000 times/second

Connection establishment itself costs resources.

Instead, clients typically reuse connections.

flowchart LR

    A[Application]

    P[Connection Pool]

    C1[Connection 1]
    C2[Connection 2]
    C3[Connection 3]

    R[(Redis)]

    A --> P

    P --> C1
    P --> C2
    P --> C3

    C1 --> R
    C2 --> R
    C3 --> R

Redis’ current client documentation explicitly includes pooling/multiplexing as a client concern, and documented clients include Python, Java, JavaScript, Go, .NET, PHP, Rust and others.


62. Connection Pool Mental Model

Instead of:

Create
Use
Destroy

Create
Use
Destroy

Create
Use
Destroy

do:

Create reusable connections
       |
       v
      Pool
       |
       +---- request
       +---- request
       +---- request

However, Redis clients differ.

Some primarily use:

Connection pools

while others rely heavily on:

Connection multiplexing

Therefore:

Follow the architecture of your chosen Redis client rather than blindly configuring an enormous pool.


63. Connection Pool Parameters to Understand

Typical settings include:

Maximum connections
Minimum idle connections
Connection timeout
Read timeout
Write timeout
Pool wait timeout
Idle timeout
Health checks
TLS settings
Authentication

Example conceptual configuration:

max_connections = 50
connect_timeout  = 1s
read_timeout     = 500ms
pool_timeout     = 500ms

Those are examples, not universal production values.

Pool sizing must consider:

Application concurrency
Number of application instances
Redis connection capacity
Command latency
Pipeline/multiplexing behavior
Traffic pattern

64. Connection Pooling Golden Rule

Do not calculate:

50 connections sounds good.

Instead calculate total system load.

Suppose:

100 application pods
×
100 Redis connections/pod
=
10,000 connections

A seemingly small per-instance pool can become enormous across a cluster.

Always think:

Per-instance configuration × number of instances


65. Redis Failure Handling

Eventually one of these will happen:

Redis unavailable
Network problem
Timeout
Connection exhaustion
Failover
High latency
Memory pressure
Application bug

Your architecture must define what happens next.

This is often more important than the happy-path Redis code.


66. Example — Redis Cache Failure

Normal:

Application
     |
     v
   Redis
     |
    HIT

Redis unavailable:

Application
     |
     X
   Redis

     |
     v
 Database

For ordinary cache data, a common strategy is:

Redis fails → bypass cache → query source of truth.

This is called:

Graceful degradation

But there is an important danger.


67. Redis Failure Can Become Database Failure

Imagine:

Redis handles 50,000 requests/sec

Redis fails.

Your fallback says:

Use database.

Now:

50,000 requests/sec → Database

The database may support only:

5,000 queries/sec.

Result:

Redis outage
    ↓
Database overload
    ↓
Application outage

This is called a cascading failure.


68. Protecting the Database During Redis Failure

Useful mechanisms include:

Short Redis timeouts
Circuit breakers
Request rate limiting
Bulkheads
Database connection limits
Load shedding
Fallback data
Stale data
Retry limits
Backoff
Jitter

Conceptually:

flowchart TD

    A[Request]

    B{Redis healthy?}

    C[Redis]

    D[Circuit Breaker]

    E{DB capacity available?}

    F[Database]

    G[Fallback / reject / stale response]

    A --> B

    B -->|Yes| C
    B -->|No| D

    D --> E

    E -->|Yes| F
    E -->|No| G

69. Never Use Unlimited Retries

Bad:

Redis timeout
    ↓
Retry
    ↓
Retry
    ↓
Retry
    ↓
Retry forever

During an outage every application instance begins retrying.

Now the recovering Redis server receives:

Massive retry storm.

Better:

Short timeout
Bounded retries
Exponential backoff
Jitter
Circuit breaker

70. Fail-Open vs Fail-Closed

Redis failure behavior depends on what Redis is doing.

Consider a cache:

Redis unavailable
↓
Query database

Usually reasonable.

Now consider a security control:

Redis stores temporary account lockout information.

Redis unavailable.

Should you:

Allow everyone?

Maybe not.

This introduces:

Fail-open vs fail-closed

Redis responsibilityPossible failure behavior
Product cacheBypass Redis
Recommendation cacheServe stale/default
Session storeUser may need to reauthenticate
Rate limiterBusiness/security decision
LockDo not blindly continue
Feature flagUse safe default
CountersQueue/degrade depending on importance

There is no universal fallback rule.

The fallback must match the business consequence.


71. Failure Handling Example

A useful cache algorithm looks conceptually like:

def get_product(product_id):

    try:
        product = redis.get(product_id)

        if product:
            return product

    except RedisError:
        # Cache unavailable.
        # Continue carefully to source of truth.
        pass

    product = database.get_product(product_id)

    try:
        redis.set(product_id, product, ex=300)
    except RedisError:
        # Do not fail user request just because cache population failed.
        pass

    return product

Notice:

Redis failure
≠
Automatically fail customer request

because Redis is only a cache in this architecture.


72. Negative Caching

Suppose someone repeatedly requests:

product:999999

which does not exist.

Without negative caching:

Request
   ↓
Redis MISS
   ↓
Database
   ↓
Not found

Again:

Redis MISS
Database
Not found

A malicious or accidental flood can repeatedly hit the database.

You can temporarily cache:

NOT_FOUND

for a short TTL.

Example:

product:999999 → NOT_FOUND
TTL = 30 seconds

This is:

Negative caching

But use short TTLs because the object might later be created.


73. Hot Keys

Suppose nearly all traffic requests:

product:iphone-latest

That single key becomes extremely hot.

                 Redis
                   |
        product:iphone-latest
         / / / / / / / / /
     millions of requests

Even if Redis overall has enough capacity, extremely skewed key access can create localized load problems.

Monitor:

Traffic distribution
Command latency
Hot keys
Network throughput
CPU

Caching architecture is not just about total key count.


74. Large Values

Do not casually store enormous payloads under one key.

Example:

cache:everything
    =
500 MB JSON

Problems include:

Network latency
Serialization cost
Memory pressure
Blocking/processing cost
Huge invalidations
Poor cache efficiency

Prefer appropriately sized objects:

product:100
product:101
product:102

when that matches your access pattern.


75. Redis Memory Is Not Infinite

Redis is often memory-centric.

That means capacity planning matters.

Think:

Number of keys
×
Average key size
×
Average value size
+
Redis structure overhead
+
Replication/persistence overhead
+
Operational headroom

Do not estimate only:

My JSON files total 5 GB,
therefore I need exactly 5 GB RAM.

Real Redis memory consumption includes metadata and internal representations.


76. TTL vs Eviction

These are different concepts.

TTL

You deliberately say:

This key should expire in 300 seconds.

Eviction

Redis is under configured memory pressure and removes keys according to the configured memory-management policy.

Therefore:

Expiration = data lifetime policy

Eviction = memory pressure policy

Do not design correctness around the assumption that a cache entry will always survive until its TTL.


77. What Should Be Cached?

Good caching candidates often have:

High read frequency
Expensive computation
Expensive DB query
Repeated identical access
Tolerance for controlled staleness
Reasonable object size

Examples:

Product catalog
Configuration
User profile summary
Search suggestions
Dashboard aggregates
Recommendation results
Reference data

78. What Should Not Automatically Be Cached?

Be cautious with:

Highly volatile authoritative financial data
One-time data rarely read again
Huge objects
Data with extremely low cache hit rate
Data where stale values are dangerous
Queries cheaper than cache management
Sensitive data without proper controls

Caching has a cost:

Code complexity
Invalidation logic
Memory
Observability
Failure modes
Staleness
Operational burden

A cache should solve a real performance or scalability problem.


79. Cache Hit Ratio

One useful metric is:

Cache Hit Ratio
=
Cache Hits
──────────────
Hits + Misses

Example:

Hits   = 9,000
Misses = 1,000

Hit ratio:

9000 / 10000
=
90%

A high hit ratio often indicates that Redis is successfully shielding the backend.

But high hit ratio alone does not prove success.

You should also ask:

Did application latency improve?

Did database load decrease?

Is the data fresh enough?

What is Redis cost?

Are hot keys forming?

Are evictions increasing?

80. Important Redis Production Metrics

Monitor at least the following categories.

Performance

Command latency
p50
p95
p99
Operations/sec
Network throughput

Cache

Hits
Misses
Hit ratio
Evictions
Expired keys

Memory

Used memory
Memory fragmentation
maxmemory utilization
Large keys

Connections

Connected clients
Connection failures
Rejected connections
Pool exhaustion

Availability

Errors
Timeouts
Failovers
Replication health
Replication lag

Backend impact

Database QPS
Database CPU
Database connection utilization
Database latency

You need both Redis metrics and application/backend metrics to understand whether caching is helping.


81. Complete Production Cache Request

Now combine the concepts.

flowchart TD

    U[Client Request]

    A[Application]

    R{Redis available?}

    H{Cache Hit?}

    C[Return Cached Value]

    CB[Circuit Breaker / Protection]

    DB[(Database)]

    S[Store in Redis with TTL + Jitter]

    RESP[Return Response]

    FAIL[Fallback / Load Shed / Error]

    U --> A

    A --> R

    R -->|Yes| H
    R -->|No| CB

    H -->|Yes| C

    H -->|No| CB

    CB -->|Backend capacity available| DB
    CB -->|Backend protected| FAIL

    DB --> S
    S --> RESP

This is much closer to a real production cache than simply:

redis.get()

82. Complete E-Commerce Example

Let’s connect all the Redis use cases into one system.

flowchart TB

    USER[Customers]

    APP[Shopping Application]

    REDIS[(Redis)]

    DB[(SQL Database)]

    PAYMENT[Payment Service]

    EMAIL[Email Worker]

    USER --> APP

    APP --> REDIS
    APP --> DB
    APP --> PAYMENT

    REDIS --> EMAIL

Redis could provide:

product:*            → product cache

session:*            → sessions

cart:*               → shopping carts

rate:*               → rate limiting

product:*:views      → counters

leaderboard:*        → sorted sets

lock:order:*         → lightweight coordination

notifications        → Pub/Sub

order-events         → Streams

One Redis system therefore exposes several data-structure capabilities, but each use case has different durability and failure requirements.


83. Example Request — Product Page

Customer requests:

GET /products/100

Process:

1. Application receives request.

2. GET product:100 from Redis.

3. HIT?
       YES
       ↓
   Return product.

4. MISS?
       ↓
   Query database.

5. Database returns product.

6. Store:
   product:100
   TTL = base + jitter

7. Return customer response.

84. Example Request — Add to Cart

Redis Hash:

HSET cart:user:100 product:500 2

Meaning:

User 100
Cart

Product 500
Quantity 2

Another:

HSET cart:user:100 product:600 1

Now:

cart:user:100
    |
    +-- product:500 = 2
    |
    +-- product:600 = 1

Add expiration if carts should disappear after inactivity.


85. Example Request — User Session

Login:

HSET session:abc123 \
    user_id 100 \
    authenticated 1

Set expiration:

EXPIRE session:abc123 1800

Any application node can now resolve:

session:abc123

86. Example Request — Product Views

Each product page:

INCR product:100:views

Across:

App-1
App-2
App-3
App-4

the counter is shared.


87. Example Request — Avoid Duplicate Order Processing

Worker attempts:

SET lock:order:7001 unique-token NX EX 15

Success:

Process order.

Failure:

Another worker currently owns the lease.

After work:

Atomic owner-token check
+
delete lock

88. Example — Live Order Notification

Publisher:

PUBLISH orders "Order 7001 confirmed"

Subscribers:

WebSocket server
Notification service
Dashboard

receive it while connected.

If the business requirement becomes:

"This message must never simply disappear."

do not rely solely on Pub/Sub.

Use something durable such as:

Redis Streams
Kafka
another durable broker

depending on requirements.


89. When Redis Should NOT Be Used

This is just as important as knowing when Redis should be used.

Do not automatically use Redis simply because:

Redis is fast.

90. Do Not Use Redis as a Replacement for Every Database

Suppose you need:

SELECT customer.name,
       SUM(order.amount)
FROM customers
JOIN orders ...
JOIN invoices ...
WHERE ...
GROUP BY ...

A relational database is designed for this type of workload.

Redis does not automatically replace:

PostgreSQL
MySQL
Oracle
SQL Server

91. Avoid Redis for Huge Cold Datasets

Imagine:

20 TB archive

that is accessed:

once every three months.

Putting the entire dataset in expensive memory may provide little benefit.

A disk/object-storage/database architecture may be more appropriate.


92. Avoid Redis for Large Binary Objects

Avoid treating Redis as:

Image repository
Video repository
Backup repository
ISO repository
Massive file store

Instead use systems designed for large objects:

Amazon S3
Google Cloud Storage
Azure Blob Storage
Object storage/CDN

Redis may cache metadata or small hot objects, but large binary storage is usually a poor fit.


93. Avoid Pub/Sub for Durable Messaging

Requirement:

PaymentCreated event MUST be processed.

Subscriber crashes.

With Pub/Sub:

Message may disappear.

That violates the requirement.

Redis officially documents Pub/Sub’s at-most-once semantics.

Use:

Redis Streams
Kafka
RabbitMQ
or another durable messaging architecture

depending on the system’s requirements.


94. Do Not Use Redis Locks as Magical Distributed Transactions

This:

SET lock:money-transfer NX EX 10

does not suddenly provide:

Global transactional correctness
Distributed consensus
Exactly-once execution
Financial settlement guarantees

Distributed systems can experience:

Network delays
Process pauses
Clock/time issues
Lease expiration
Failover
Partial failure

Use Redis locking for problems whose correctness model fits a lease-based lock.


95. Avoid Redis When Caching Gives No Benefit

Suppose:

Request A reads unique data once.

Request B reads different unique data once.

Request C reads different unique data once.

Cache hit ratio approaches:

0%

Now Redis adds:

Network call
Serialization
Memory
Infrastructure cost
Operational complexity

without meaningfully reducing database work.

Do not cache merely because caching is fashionable.


96. Redis Decision Matrix

RequirementRedis?Feature
Fast product cacheString / Hash
User sessionsHash/String + TTL
Distributed counterINCR
LeaderboardSorted Set
Unique membershipSet
Live ephemeral notificationsPub/Sub
Durable event processingStreams
Approximate unique visitor countHyperLogLog
Temporary coordinationSET NX EX
Large relational joinsUse relational DB
Huge video archiveUse object storage
Durable Pub/Sub-style event history❌ Pub/SubUse Streams/Kafka/etc.
Strong consensusUse appropriate coordination mechanism
Low reuse / zero cache hitsUsually ❌Cache may add no value

97. Cache-Aside vs Write-Through Summary

CACHE-ASIDE

Application
   |
   +--> Redis
   |
   +--> Database

Application owns cache logic.


READ-THROUGH

Application
   |
   v
Cache abstraction
   |
   +--> Redis
   |
   +--> Database loader

Cache abstraction owns loading logic.


WRITE-THROUGH

Application
   |
   v
Cache abstraction
   |
   +--> Cache
   |
   +--> Database

Both are updated on the write path.


98. TTL Summary

Never ask only:

What TTL should Redis use?

Ask:

How stale may this data safely become?

How often does it change?

How expensive is reconstruction?

What happens when thousands of keys expire?

Can we actively invalidate it?

Then choose:

TTL
+
Jitter
+
Invalidation
+
Stampede strategy

99. Cache Invalidation Summary

Four common mechanisms:

1. TTL expiration

2. Delete on database change

3. Update cache on database change

4. Event-driven invalidation

A strong production architecture often combines:

Active invalidation
+
TTL safety net

100. Stampede Summary

Problem:

Popular key expires
       ↓
Thousands of MISSes
       ↓
Thousands of DB queries
       ↓
Database overload

Solutions include:

TTL jitter

Single refresher / mutex

Stale-while-revalidate

Request coalescing

Early refresh

Backend rate protection

101. Connection Pooling Summary

Do:

Application process
       |
       v
Reusable Redis client
       |
Pool / multiplexed connections
       |
       v
Redis

Avoid:

Every request
    ↓
New connection
    ↓
Redis
    ↓
Close connection

And remember:

pool size
×
application instance count
=
total potential connections

102. Failure Handling Summary

For each Redis use case ask:

What happens if Redis disappears for 30 seconds?

Cache:

Maybe bypass Redis.

Session:

Maybe temporarily unavailable/re-authenticate.

Rate limiter:

Choose fail-open or fail-closed intentionally.

Lock:

Do not blindly continue.

Pub/Sub:

Messages during disconnect may be lost.

Counter:

Decide whether temporary loss/unavailability matters.

The same Redis failure cannot have one identical fallback strategy for every use case.


103. Production Redis Golden Rules

Rule 1

Treat the database as the source of truth when Redis is being used purely as a cache.

Rule 2

Use the Redis data structure that naturally represents the problem.

Rule 3

Do not cache everything.

Rule 4

Give temporary cache data a deliberate expiration strategy.

Rule 5

Use TTL jitter for large groups of similarly expiring keys.

Rule 6

Design cache invalidation before production.

Rule 7

Protect the database from cache failure.

Rule 8

Use bounded retries and timeouts.

Rule 9

Reuse Redis connections through the architecture supported by your client.

Rule 10

Monitor hits, misses, memory, evictions, latency and backend load.

Rule 11

Do not use Pub/Sub when you require durable delivery.

Rule 12

Treat Redis locks as leases, not magical distributed transactions.

Rule 13

Use unique lock ownership tokens.

Rule 14

Never depend blindly on stale cached data for critical decisions.

Rule 15

Design Redis failure behavior before Redis actually fails.


104. The Complete Mental Model

If you remember only one diagram from this tutorial, remember this:

flowchart TB

    CLIENT[Clients]

    APP[Application Layer]

    POOL[Redis Client / Connection Pool]

    REDIS[(Redis)]

    DB[(Authoritative Database)]

    EVENTS[Durable Event System]

    CLIENT --> APP

    APP --> POOL

    POOL --> REDIS

    APP --> DB

    APP --> EVENTS

    REDIS -->|Cache / Sessions / Counters / Locks| APP

    DB -->|Source of Truth| APP

Redis is positioned where fast shared state creates value.


105. Redis in One Sentence

Redis is a high-speed shared data-structure store that applications commonly use to reduce expensive work and coordinate temporary state, but every Redis use case must have deliberate policies for freshness, expiration, durability and failure.


106. Final Topic Map

You can now connect the complete learning journey:

flowchart TD

    A[Redis Fundamentals]

    B[Redis Data Structures]

    C[Caching]

    D[Cache-Aside]

    E[Read/Write-Through]

    F[TTL]

    G[Cache Invalidation]

    H[Stampede & Staleness]

    I[Pub/Sub]

    J[Sessions]

    K[Counters]

    L[Distributed Locks]

    M[Connection Pooling]

    N[Failure Handling]

    O[When NOT to Use Redis]

    P[Production Redis Architecture]

    A --> B
    B --> C
    C --> D
    D --> E
    E --> F
    F --> G
    G --> H

    H --> I
    H --> J
    H --> K
    H --> L

    I --> M
    J --> M
    K --> M
    L --> M

    M --> N
    N --> O
    O --> P

107. Final GOLD Standard Comparison

TopicCore QuestionKey Redis Concept
RedisWhy use it?Fast shared state
Data structuresHow should data be represented?String/Hash/List/Set/ZSet/Stream
Cache-asideWho manages cache misses?Application
Read-throughWho loads missing data?Cache abstraction
Write-throughHow are writes synchronized?Cache + DB write path
TTLHow long may data live?Expiration
InvalidationHow do we remove stale copies?Delete/update/event
StampedeWhat if many misses occur together?Jitter/locking/SWR
Stale dataHow old may data safely become?Freshness policy
Pub/SubNeed real-time ephemeral broadcast?PUBLISH / SUBSCRIBE
SessionsNeed shared temporary user state?Hash/String + TTL
CountersNeed atomic shared numbers?INCR
Lightweight locksNeed temporary coordination?SET NX EX/PX
PoolingHow should applications connect efficiently?Reuse/multiplex
Failure handlingWhat happens when Redis fails?Fallback/circuit breaker
Don’t use RedisIs Redis actually the right system?Architectural judgment

108. The Most Important Redis Lesson

Learning Redis commands is relatively easy:

GET
SET
DEL
EXPIRE
HSET
SADD
ZADD
INCR
PUBLISH
SUBSCRIBE

The difficult—and valuable—part is learning to answer:

Should this data be cached?

Who owns the truth?

How long may the cached copy live?

How is it invalidated?

What if the key expires during heavy traffic?

What if Redis goes down?

What if the database goes down?

Can stale data hurt the business?

Do I need durability?

Do I need atomicity?

Do I actually need Redis?

When you can answer those questions, you are no longer simply using Redis commands.

You are designing a production Redis architecture.

Related Posts

Kafka Master Tutorials Series: 7 Topics, Partitions, Consumers, Consumer Groups & Lag

Developer Planning Guide for Correct Mapping, Scaling, Reliability and Performance Audience: Developers, students, freshers, architects, platform engineersTraining context: Confluent Kafka ClusterGoal: Remove confusion around how Kafka Topics, Partitions, Producers, Consumers,…

Read More

Kafka Master Tutorials Series: 6 – Kafka Consumer Deep Dive

Consumer Groups, Parallelism, Offsets, Rebalancing, Failover, Consumption Patterns and Production Tuning Audience: Students and freshers with no previous Kafka experienceGoal: Start with “What is a consumer?” and finish with…

Read More

Kafka Master Tutorials Series: 5 – Deep Dive Into Kafka Producers

From send() to Broker ACK: Keys, Partitions, Batching, Retries, Reliability, Latency and Performance Tuning Audience: Students and freshers with no prior Kafka experienceGoal: Build from producer fundamentals to production-grade Kafka producer…

Read More

Kafka Master Tutorials Series: 4 – Confluent Cloud Kafka — Production Checklist

1. Cluster Architecture Recommended architecture: 2. Capacity Planning Confluent recommends monitoring cluster load closely. Sustained load around 70–80% is a reason to consider adding CKUs, while above…

Read More

Kafka Master Tutorials Series: 3 -Capacity Planning in Confluent Cloud

1. What is Kafka Capacity Planning? Capacity planning means calculating how much Kafka capacity your application needs before production traffic arrives. In simple words: How big should…

Read More

Kafka Master Tutorials Series: 2 – How Kafka Works & its Architecture & workflow

Kafka Architecture 1. Learning objectives By the end of this tutorial, a student should understand: 2. Start with the simplest Kafka architecture At the highest level: For…

Read More