Design a flash sale system that survives the rush

When a hot item goes on sale, thousands of users hit one product at once. We design for the spike without overselling or crashing.

A burst of arrows converging on a single product

Goal: sell a limited number of items at a special time, when traffic suddenly jumps by 100x, without overselling and without going down.

What makes it hard

  • Huge, short spike, often at an exact time.
  • Everyone wants the same few items, so one database row becomes a hot spot.
  • Bots and scripts join in.
  • Overselling or crashing hurts trust and money.

Strategy: reduce the work at each layer

1. Static content on a CDN. The product page, images and scripts should be cached at the edge, so only the "buy" action reaches your servers.

2. Pre-warm. Warm caches and scale servers before the start time.

3. Waiting room / traffic shaping. Let users into the purchase flow in controlled batches. A queue with a position number is fairer and protects the backend.

4. Rate limiting and bot defence. Limit per user, IP and device, use CAPTCHAs or proof-of-work for suspicious traffic, and require login before the sale.

5. Stock in Redis. Keep the available count in Redis and decrement atomically (DECR, or a Lua script that checks and decrements). If the result is negative, the item is sold out and the request is rejected immediately, without touching the database.

6. Queue the orders. Successful decrements push an order request to a message queue. Workers create orders at a steady pace the database can handle. The user sees "processing" and then confirmation.

7. Payment window. Hold the item for a short time (for example 10 minutes). If payment fails, return the unit to stock.

Avoid the hot row

Instead of one stock row, split stock into several buckets (for example 10 counters of 100 units) and pick one at random. This spreads the contention.

Consistency and safety

  • Redis is fast but can lose data in a crash, so reconcile with the database and never sell more than the real stock. The database remains the final authority.
  • Make order creation idempotent so retries do not duplicate orders.
  • One purchase per user, enforced by a unique key.

Degrade gracefully

If load is too high, return a quick "sold out" or "try again" response instead of timing out. Shed load early.

Observability

Watch queue length, error rate, Redis latency and database load during the event, and have a kill switch.

Takeaway: push work to the edge, shape traffic with a waiting room, decrement stock atomically in Redis, queue order creation, and fail fast.


System Design series, Part 3 (case studies): 14 of 16. Previous: Design an e-commerce checkout system.

Keep reading