Design and Technical Solutions for a High‑Concurrency Flash Sale (秒杀) System
This article analyzes the challenges of building a flash‑sale system—such as overselling, massive concurrent requests, URL exposure, and database strain—and presents a comprehensive backend design that includes separate databases, dynamic URLs, Redis clustering, Nginx load balancing, rate‑limiting, asynchronous order processing, and service degradation strategies.
Problems to Consider in a Flash‑Sale System
Flash‑sale (秒杀) platforms like JD or Taobao face critical issues: overselling when stock is limited, extremely high request concurrency within a few minutes, automated bots repeatedly hitting the API, predictable URLs that can be harvested, database overload when the sale shares the same DB as other services, and the sheer volume of requests that can overwhelm caches and servers.
Overselling
If only 100 items are stocked but 200 orders are placed, the business suffers severe loss; preventing this is the top priority.
High Concurrency
Thousands of users flood the system simultaneously, risking cache breakdown and database crashes.
Interface Abuse
Bots may send hundreds of requests per second; the system must filter out invalid or duplicate calls.
Predictable URLs
Users can discover the sale URL via browser dev tools and bypass front‑end controls, so the URL must be hidden or dynamically generated.
Database Design
Sharing the main database with other services can cause cascading failures; a dedicated flash‑sale database with separate order and product tables isolates the load.
Massive Request Handling
Even a Redis cache may be insufficient for tens of thousands of QPS; a Redis cluster with sentinel mode is recommended.
Design and Technical Solutions
Flash‑Sale Database Schema
Two core tables are required: miaosha_order for orders and miaosha_goods for product details, plus optional product and user tables for richer information.
Dynamic Sale URL
Generate the sale endpoint by MD5‑hashing a random string; the front‑end requests the actual URL from the back‑end, preventing pre‑knowledge of the endpoint.
Static Page Generation
Render product description, parameters, and reviews into a static HTML page (e.g., using FreeMarker) so that user requests bypass the application server and database entirely.
Redis Cluster
Deploy Redis in a clustered or sentinel configuration to handle high read‑write traffic and avoid cache penetration.
Use Nginx as Front‑End Proxy
Nginx can handle tens of thousands of concurrent connections and forward them to a Tomcat cluster, greatly improving throughput.
SQL Optimization
Combine stock check and decrement into a single UPDATE statement with optimistic locking (version field) to prevent overselling.
Redis Pre‑Decrement Stock
Initialize stock in Redis (e.g., redis.set(goodsId, 100) ) and atomically decrement via Lua scripts; on order cancellation, increase the stock while ensuring it never exceeds the original amount.
Rate‑Limiter (Token Bucket)
Apply Guava's RateLimiter to generate tokens at a controlled rate. Example implementation:
public class TestRateLimiter {
public static void main(String[] args) {
// 1 token per second
final RateLimiter rateLimiter = RateLimiter.create(1);
for (int i = 0; i < 10; i++) {
double waitTime = rateLimiter.acquire();
System.out.println("Task " + i + " waited " + waitTime);
}
System.out.println("Finished");
}
}A second variant uses tryAcquire(timeout, TimeUnit.SECONDS) to reject requests that cannot obtain a token within a short window:
public class TestRateLimiter2 {
public static void main(String[] args) {
final RateLimiter rateLimiter = RateLimiter.create(1);
for (int i = 0; i < 10; i++) {
long timeout = 0L; // 0.5 seconds in real code
boolean ok = rateLimiter.tryAcquire(0.5, TimeUnit.SECONDS);
if (!ok) continue; // drop request
System.out.println("Task " + i + " executed");
}
System.out.println("Ended");
}
}Asynchronous Order Processing
After passing rate‑limiting and stock checks, push the order request to a message queue (e.g., RabbitMQ). Consumers handle the actual order creation, allowing the front‑end to return quickly and providing retry or compensation mechanisms for failures.
Service Degradation
If a service crashes during the sale, employ circuit‑breaker tools like Hystrix to fall back to a friendly error response instead of a server error.
Asynchronous Ordering
Queue‑based processing decouples the request path, smooths traffic spikes, and improves reliability.
Service Degradation
Implement fallback services to maintain a graceful user experience during partial outages.
Summary
The presented architecture—dedicated database, dynamic URLs, static pages, Redis cluster, Nginx proxy, optimized SQL, token‑bucket rate limiting, asynchronous queue, and circuit‑breaker degradation—can comfortably support hundreds of thousands of concurrent flash‑sale requests; larger scales would require further sharding, Kafka queues, and additional Redis clusters.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.