Design and Implementation of a Java-Based Flash Sale (Seckill) System
This article explains the architecture and Java code for a high‑concurrency flash‑sale system, covering request distribution, pre‑processing, queue selection, transaction handling, and database interaction to efficiently manage limited‑stock purchases under massive traffic.
The article describes a flash‑sale (seckill) system where each server sells a limited number of products and users are randomly assigned to machines for processing.
System Overview : The system must handle a huge number of concurrent users competing for limited items, requiring a distributed cluster and Java implementation.
Module Design includes:
User request distribution using Nginx/Apache.
Pre‑processing to reject requests when inventory is exhausted.
Request handling that packages valid requests into transactions for the database.
Database interface providing RPC calls for inventory checks.
User Request Pre‑Processing Module – after HTTP distribution, the pre‑processor checks remaining stock via an RPC call and either queues the request or rejects it. Example code:
package seckill;
import org.apache.http.HttpRequest;
/**
* Pre‑processing stage: reject unnecessary requests, queue necessary ones.
*/
public class PreProcessor {
private static boolean reminds = true;
private static void forbidden() {
// Do something.
}
public static boolean checkReminds() {
if (reminds) {
// Remote check via RPC.
if (!RPC.checkReminds()) {
reminds = false;
}
}
return reminds;
}
/**
* Every HTTP request passes this method.
*/
public static void preProcess(HttpRequest request) {
if (checkReminds()) {
RequestQueue.queue.add(request);
} else {
forbidden();
}
}
}Concurrent Queue Selection : Java provides ConcurrentLinkedQueue , LinkedBlockingQueue , and ArrayBlockingQueue . Because enqueue demand far exceeds dequeue, ConcurrentLinkedQueue is chosen.
package seckill;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.http.HttpRequest;
public class RequestQueue {
public static ConcurrentLinkedQueue
queue = new ConcurrentLinkedQueue
();
}User Request Module sends successful bids to the database queue:
package seckill;
import org.apache.http.HttpRequest;
public class Processor {
/**
* Send a seckill transaction to the DB queue.
*/
public static void kill(BidInfo info) {
DB.bids.add(info);
}
public static void process() {
BidInfo info = new BidInfo(RequestQueue.queue.poll());
if (info != null) {
kill(info);
}
}
}
class BidInfo {
BidInfo(HttpRequest request) {
// Do something.
}
}Database Module uses an ArrayBlockingQueue to temporarily store potentially successful requests and performs count‑down operations:
package seckill;
import java.util.concurrent.ArrayBlockingQueue;
public class DB {
public static int count = 10;
public static ArrayBlockingQueue
bids = new ArrayBlockingQueue
(10);
public static boolean checkReminds() {
// TODO
return true;
}
// Single‑threaded operation
public static void bid() {
BidInfo info = bids.poll();
while (count-- > 0) {
// insert into table Bids ...
// select count(id) from Bids where item_id = ?
// If inventory exhausted, set reminds = false.
info = bids.poll();
}
}
}Future Improvements summarize a more refined approach: distribute requests via a cache layer (e.g., OCS), route to low‑load machines, perform atomic count operations in the cache, and let the database finalize the transaction, with fallback handling when stock runs out.
Overall, the article provides a practical, code‑rich guide for building a scalable flash‑sale backend using Java concurrency utilities and distributed request handling.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
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.