DEV Community

Cover image for Big Billion Days - System Design
Bhanu partap
Bhanu partap

Posted on AI-assisted

Big Billion Days - System Design

Imagine you are sitting in a shoe shop with your friend. You see a pair of shoes and the display says "Only 5 left!" so you quickly buy all 5.

  • Your friend, sitting right beside you, sees the same sign and tries to order 5 more. But wait.. there were only 5 pairs in total! How can the system sell 10 shoes when only 5 existed? 😅

This is exactly what happens in production when your cache holds stale data.

Your system flows like this: Client → Node.js → Redis → PostgreSQL.

Redis is super fast but it can hold outdated information while PostgreSQL sits there with the actual truth. So how do you fix this without killing performance?

Let us break it down simply.
Visualize the Problem (The Shop Window Analogy)

Think of PostgreSQL as your warehouse (Godown). This is where the real stock and real prices live. It is slow but accurate.

Now think of Redis as your shop's display window. Customers look at the window to decide what to buy. Looking at the window is very fast (20ms), but going to the warehouse takes time.

So what went wrong?

A customer bought the last pair of shoes. The warehouse (Postgres) updated the stock to zero. But the display window (Redis) still shows "Stock Available: 5" because nobody updated it.

The next customer sees the window, places an order, and gets angry when the system says "Out of Stock" at checkout. They feel cheated! 😤
In production terms, Redis has stale data and Postgres has fresh data. They are out of sync.

Key Terms Made Simple

  • Cache Hit means the customer found what they needed in the display window. Fast and cheap.
  • Cache Miss means the window was empty so you had to run to the warehouse. Slow but accurate.
  • Stale Data means the window shows old info. Like displaying "$100" when the warehouse price already changed to "$120".
  • Invalidation means removing or marking old data in the cache so nobody trusts it anymore.

What caching strategy does your team use? Drop your answer below 👇


Decoding the Options
Now let us figure out what to do when a write happens (like stock changing or price updating).

Option A: Write-through ❌ (Performance Killer)
Every time you update stock, you update both Redis AND Postgres at the same time. Only when both succeed do you tell the user "Done".
Sounds perfect right? Cache is never stale.
But here is the problem. Every single write now waits for two systems. At 40K RPS during a sale, this becomes a massive bottleneck. Latency shoots up and users start abandoning carts. Not good..

Write through

Option B: Write-behind ⚠️ (Risk of Data Loss)
You update only Redis and instantly tell the user "Success!". A background worker slowly syncs Redis changes to Postgres later.
Writes feel lightning fast. User experience is smooth.
But if Redis crashes before the worker syncs to Postgres, that data is gone forever. In e-commerce, losing stock or payment data is unacceptable. This creates financial nightmares 💸

write behind

Option C: Cache-aside plus Explicit Invalidation ✅ (The Winner)
For reads, check Redis first. If missing, fetch from Postgres and populate Redis.
For writes, update Postgres directly (it is your source of truth). Then immediately delete that key from Redis.
When the next customer checks that product, they get a cache miss. The app fetches fresh data from Postgres and repopulates Redis automatically.
Simple. Reliable. Consistent. No performance sacrifice.
Yes there is a tiny race condition risk if two people update simultaneously, but this is the industry standard for e-commerce for a reason :)

DB -> Cache

Option D: Read-through ❌ (Wrong Place for Logic)
Redis itself becomes smart. If it does not have data, it connects to Postgres and fetches it without the app knowing.
Great for reads. Terrible for writes.

Auto

If an admin changes a price, how does Redis know to invalidate its own copy? Read-through alone does not solve the stale write problem.
The Correct Answer and Logic
Correct Answer: C) Cache-aside (lazy loading) where the app writes directly to Postgres, invalidates the cache key, and lets the next read repopulate.

The logic is beautifully simple.
We want writes to be fast, so we write directly to Postgres.
We want data to stay consistent, so we delete the Redis key.
We want the next read to be fresh, so the cache miss triggers a clean repopulation.

Stale data disappears because the old cached value is gone before anyone can read it again.

Next time you build an inventory system, remember the shoe shop. Do not let your display window lie to your customers :)

SystemDesign #Caching #Redis #BackendEngineering #ECommerce

Top comments (0)