Big Billion Days is live today. Millions of people are hitting buy right now. And some of them will pay, get a confirmation, and still receive an order cancelled message 10 minutes later. This is not a bug. It is a design decision. Let me explain it.
Raat ke 12 baje. 10 lakh log ek saath buy dabate hain. Ek hazar iPhones stock mein hain.
This is one of the hardest problems in backend engineering. Not because the solution is complicated. Because every individual piece looks simple, and it is the combination that breaks everything at scale.
I want to walk you through exactly what happens from the moment you tap buy to the moment you get that cancellation message. Because if you understand this properly, you can answer one of the most common system design interview questions: design a flash sale.
Let us go through it layer by layer.
The Numbers First
Before any design, you need to understand the scale you are building for.
During Big Billion Days, Flipkart sees around 15 lakh requests per second the moment the sale opens. Their order processing capacity is around 2000 to 2500 orders per second. That means for every 1 person who actually places an order, roughly 750 people sent a request that has to be handled, rejected, or queued without crashing the system.
Day 1 of BBD 2025 saw 33 crore visits. Amazon's Great Indian Festival saw 38 crore visits the same day. These are not theoretical numbers. This is what the system actually handled.
And the first time Flipkart tried this, in 2014, they crashed. Sachin and Binny Bansal personally wrote an apology letter where they admitted that some orders for sold out products went through because the system could not keep up. They had deployed 5000 servers and prepared for 20x traffic. The actual traffic was higher.
That 2014 failure is the reason every decision in this design exists.
Layer 1: Keep Most Traffic Away From Your Servers
The first thing you do is make sure most requests never reach your core systems at all.
When someone opens the Flipkart app on BBD morning, they are loading product pages, banners, category listings, and static content. None of that needs to come from your main servers. It comes from CDN servers placed in cities across India, physically close to the user.
Static content gets served from the nearest edge. Load on your origin servers drops massively before the sale even starts.
The traffic that does reach your servers goes through a load balancer that distributes it across hundreds of application servers. No single server drowns. Load gets spread.
But here is the important part. Even with CDN and load balancing, 15 lakh requests per second trying to actually buy something is too much for any system to process directly. So before a user even gets close to the buy flow, they hit a waiting room.
Layer 2: The Waiting Room
This is the piece most people skip when they think about flash sale design.
You cannot let everyone rush the checkout simultaneously. It is the digital equivalent of opening one door to a stadium and letting everyone run in at once.
A virtual waiting room puts every user in a queue. You are shown your position. The system lets through only as many users per second as your checkout flow can actually handle cleanly, maybe 3000 to 5000 per second. Everyone else waits their turn.
Yaha se asli ladai shuru hoti hai.
The users who make it through the waiting room actually reach the buy flow. And here is where the hardest problem in the entire design lives.
Layer 3: The Stock Problem and Race Condition
You have 1000 iPhones. 10 lakh people want one.
The most obvious approach: check stock in database, if greater than zero, subtract one, place order.
Wrong. Completely wrong at scale.
Here is what happens. Rahul and Priya both tap buy at the exact same millisecond. Both requests reach your server simultaneously. Both check the database at the same time. Both see stock = 1. Both subtract 1. Both get order confirmed. Now your stock is at -1 and you have oversold.
This is called a race condition. It is not a theoretical concern. The 2014 Flipkart failure included exactly this. Some orders went through for products that were already sold out because multiple requests read the same stock value simultaneously.
The fix is atomic operations.
Instead of reading and writing stock in two separate steps, you do it in one single step that cannot be interrupted or run simultaneously with another request.
You keep the stock counter in Redis, which runs in memory and executes every command one at a time, in order. The command you send is: decrement this counter and tell me the new value. If the new value is zero or above, the phone is yours. If the new value is negative, stock is gone, increment it back, tell the user sold out.
Even if Rahul and Priya arrive simultaneously, Redis processes their requests one after the other. The first one gets the last phone. The second one gets sold out. No overselling. No -1 stock. No apology letter required.
Layer 4: Orders Go Into a Queue, Not Directly to Database
Phone secured. Order placed.
Your first instinct might be to write the order directly to the database immediately. At 2000 orders per second, that is 2000 simultaneous database writes every second. Plus all the reads happening at the same time for stock checks, user authentication, address lookups.
Direct database writes at this scale causes the database to become the bottleneck. It slows. Everything behind it slows.
Instead, confirmed orders go into a message queue like Kafka. The order write happens asynchronously. Workers pick up orders from the queue and write them to the database at a controlled, steady pace. The spike in orders never hits the database directly. The queue absorbs it.
This is the same idea as a buffer. Ek dam se sab kuch database pe mat dalo. Line lagao, kaam karo.
Layer 5: The 10-Minute Hold and Why Your Order Gets Cancelled
This is the part that explains the experience you have actually lived.
You got the phone. Order confirmed. But payment is still pending.
The system reserves that phone for you for 10 minutes. A timer starts. During those 10 minutes, nobody else can buy that phone. It is on hold for you.
You open your payment app, authenticate, and confirm. Payment goes through in 45 seconds. Order is locked in. Timer cancelled.
But sometimes payment takes longer. Your UPI app hangs. The bank's server is slow because 50 lakh people are doing transactions simultaneously on BBD morning. The bank sends a response after 12 minutes.
Your 10 minute hold has already expired. The system released that phone back to stock 2 minutes ago. Another user bought it. Your payment just arrived for a phone that no longer belongs to you. The system detects this mismatch, cancels your order, and refunds your money.
This is not a bug. It is the intentional behavior. The alternative is worse.
The alternative is holding that phone indefinitely until your payment clears. But what if you abandon the checkout entirely? What if everyone who gets to checkout holds a phone but never pays? The entire stock gets locked up by people who may never complete the purchase. Nobody else can buy the phone. Flipkart cannot sell the phone. Everyone loses.
So the rule is: overselling is worse than cancelling. If a payment arrives after the hold expires and the product is gone, cancel and refund. Every single time, no exceptions.
Layer 6: What Happens When Everyone's Hold Expires at the Same Time
Here is the subtle problem inside the problem.
When the sale opens at midnight and 5 lakh people all secure a product within the first 60 seconds, all of their 10-minute holds expire at roughly the same time. 10 minutes later, a massive chunk of held stock gets released back simultaneously. Everyone who was waiting gets notified. Another wave of 5 lakh people hits buy again.
You have essentially recreated the original midnight rush, 10 minutes later.
This is why smart systems add a small random offset to hold timers. Instead of everyone's timer being exactly 10:00, some are 9:48, some are 10:15, some are 10:31. The releases happen in a stream rather than a wave. The second rush is spread over several minutes instead of hitting simultaneously.
Same idea as the jitter fix from cache stampede. Spread the load. Never let everything expire at the same time.
The Full Design in One Line
Spread the crowd with CDN, load balancer, and waiting room. Reserve stock atomically in Redis so nobody oversells. Write orders through a queue so the database does not drown. Hold stock for 10 minutes during payment and cancel if the hold expires. Add jitter to everything that could expire simultaneously.
Scale comes from spreading load across many layers. Correctness comes from keeping the one number that must never be wrong, stock, in one place, updated atomically, with one clear rule.
What the Interviewer Is Actually Testing
When a system design interviewer gives you this question, they are not asking you to list technologies. They are asking whether you understand where things break.
Most people say: database, cache, load balancer. They get the components right but miss the failure modes.
The failure modes are: race condition on stock (fix: Redis atomic DECR), database spike from direct writes (fix: Kafka queue), payment delay after hold expires (fix: cancel and refund, never oversell), synchronized cache expiry (fix: jitter).
If you can walk through each failure mode and explain the specific fix, and more importantly explain why that failure mode exists in the first place, you are giving an answer that most candidates do not.
The question is easy to answer at the surface. It is hard to answer at the layer where things actually break.
Today is Big Billion Days. Somewhere right now, someone is getting an order cancelled after paying. Now you know exactly why.
If this kind of breakdown is useful, I write about system design, RAG, and AI engineering here and on LinkedIn. Code and projects on GitHub.



Top comments (0)