V
System Design #9 Hello Interview Flash Sale Guide Inventory: 10,000 Units • 500k+ Users

Design a Flash Sale System

High-concurrency e-commerce architecture: Virtual Waiting Room (Queue-it admission), In-Memory Redis Lua Atomic Reservation (Zero DB row locks), Asynchronous Kafka Order Processing, and Delayed Restock Timers for 0% overselling guarantee.

Guarantee: Zero Overselling Under 500k RPS
Stock Remaining10000 / 10,000Strict Atomic Decrement
Peak Contention500,000 UsersWaiting Room Token Metered
Reservation Latency< 3.2ms P99Redis Single-Threaded Lua
Reservation Window10 MinutesAuto-Restock on Timeout
Overselling Rate0.00%Mathematical Guarantee
Simulate Flows:
FLASH SALE SYSTEM CORE ARCHITECTURE (ZERO DB ROW LOCKS • ATOMIC RESERVATIONS) POST /reservationsValidate TokenAtomic Lua Check & DecrEmit Order EventConsume EventWrite ACID OrderStart 10-Min TimerOn Expiry / Decline: redis.call('INCRBY', stock, 1) [Auto-Restock]Buyer Client & Waiting• Virtual Waiting Room• Metered Admission Token• Live 10-Min Countdown• Direct Stripe iFrame PayAPI Gateway & Auth• Verify HMAC Queue Token• Rate Limit Abusive IPs• Drop Unmetered Surges• Sub-Millisecond GateFlash Sale Service• Stateless Microservice• Invokes Redis Lua Script• Generates Reservation ID• Emits Order EventRedis Atomic Lua Inventory• Single-Threaded RAM• Atomic Check & DECRBY• Zero DB Row Locks• 100k+ Ops/Sec < 0.5ms• 0% Overselling GuaranteeKafka Order Bus• Buffers 10,000 Orders• Decouples DB Writes• Guaranteed DeliveryOrder & Payment Service• Consumes Order Events• Stripe Webhook Receiver• Marks Purchase COMPLETEPostgreSQL Database• Purchases & Orders• Permanent ACID Log• Zero Hot Row LockingExpiry & Restock Manager• 10-Min Dead Man Timer• Auto-INCRBY Redis Stock• Recovers Abandoned Units
Virtual Waiting Room Admission Redis Lua Atomic Reservation Asynchronous Kafka Decoupling 10-Min Auto-Restock Pipeline
Click any component box to view Hello Interview deep dive

Core Requirements (Hello Interview)

Functional 1: Users can view flash sale item details and real-time available inventory count.
Functional 2: Users can secure/reserve an available unit for a 10-15 minute window while sale is active.
Functional 3: Users complete payment before the countdown expires; abandoned units auto-return to inventory.
Non-Functional: Zero overselling, extreme write scalability under 500k RPS, bot mitigation, and sub-5ms reservation latency.

What is Expected at Each Level?

Mid-Level: Identify the race condition on inventory, propose basic database transactions or distributed locks, separate viewing from purchasing.
Senior: Articulate why DB row locks fail under 500k users. Design atomic Redis Lua script reservation, 10-min delayed restock queues, and asynchronous checkout via Kafka.
Staff+: Present end-to-end defense-in-depth: Virtual Waiting Room (fair queuing & token metering), multi-tier bot defense, atomic in-memory inventory reservation, and zero-loss audit logging.

In-Memory Redis Inventory (Atomic Lua)

Role & Overview

In-memory Redis instance holding the live flash sale inventory counter. Executes an atomic Lua script that decrements stock only if available inventory > 0, completely avoiding relational database row-level locking.

Architecture Implementation

Lua script checks `local stock = redis.call('GET', KEYS[1])`. If `tonumber(stock) >= tonumber(ARGV[1])`, performs `redis.call('DECRBY', KEYS[1], ARGV[1])` and saves reservation record. Runs single-threaded in RAM in < 0.5ms!

Maintaining Consistency Under Extreme Contention
❌ Bad Solution: Relational DB Row Locks: `UPDATE products SET stock = stock - 1 WHERE id = 1 AND stock > 0`. 100,000 concurrent updates serialize on a single disk row lock, exhausting connection pools and causing timeouts.
⚠️ Good Solution: Pessimistic Locking / Distributed Lock: Redlock on product ID. Still serializes requests, adding network round-trip overhead.
⭐ Great Solution: Atomic In-Memory Lua Script in Redis: Redis executes Lua scripts atomically in single-threaded memory. Millions of checks/decrements process sequentially at 100k+ ops/sec with zero lock contention and mathematically guaranteed zero overselling.
Specification & Snippet
-- Redis Atomic Inventory Lua Script
local key = KEYS[1] -- 'product:123:stock'
local userKey = KEYS[2] -- 'product:123:user:' .. ARGV[2]
local qty = tonumber(ARGV[1])

-- Prevent duplicate reservations per user
if redis.call('EXISTS', userKey) == 1 then
    return -2 -- Already reserved
end

local stock = tonumber(redis.call('GET', key) or 0)
if stock >= qty then
    redis.call('DECRBY', key, qty)
    redis.call('SET', userKey, 'reserved', 'EX', 600) -- 10 min TTL
    return stock - qty -- Success: remaining stock
else
    return -1 -- Out of stock
end