Designing a High-Concurrency Flash Sale System Using Redis Caching and Lua Scripts
This article explains how to design a high‑concurrency flash‑sale (秒杀) system by leveraging browser and CDN caching, read‑write split Redis for traffic filtering, Lua scripts for atomic stock deduction, master‑slave Redis for fast inventory updates, and Redis‑based message queues for asynchronous order processing.
Background
Flash‑sale (秒杀) activities are a common low‑price promotion method for e‑commerce platforms, generating massive traffic spikes that can be dozens or hundreds of times higher than normal, which challenges system stability and fairness.
Characteristics of Flash Sales
Flash sales consist of three stages: pre‑sale where users continuously refresh the product page, sale start where users click the purchase button causing a request peak, and post‑sale where a small fraction of successful orders continue to poll for status while most users keep refreshing.
System Architecture
To reduce the load on the backend, the static parts of the flash‑sale product page are cached in the browser and CDN, separating it from the regular product page. Only the purchase button remains dynamic.
Traffic Filtering with Read‑Write Split Redis
Redis is used as the second layer of traffic interception. The product’s total stock, start flag, and accepted order count are stored as follows:
"goodsId_count":100 // total stock
"goodsId_start":0 // start flag
"goodsId_access":0 // accepted ordersThe handling flow is:
Before the sale, the service reads goodsId_start (0) and returns “not started”.
The data‑control module sets goodsId_start to 1 to mark the sale start.
During the sale, the service increments goodsId_access and calculates remaining stock as (goodsId_count - goodsId_access).
When goodsId_access reaches goodsId_count, further requests are blocked.
Stock Deduction with Master‑Slave Redis and Lua
Successful orders are processed by a master‑slave Redis cluster (≈100k QPS). Each product’s inventory is stored as a hash:
{
"Total":100,
"Booked":100
}An atomic Lua script checks availability and updates the booked count:
local n = tonumber(ARGV[1])
if not n or n==0 then return 0 end
local vals = redis.call("HMGET", KEYS[1], "Total", "Booked")
local total = tonumber(vals[1])
local booked = tonumber(vals[2])
if not total or not booked then return 0 end
if booked + n <= total then
redis.call("HINCRBY", KEYS[1], "Booked", n)
return n
end
return 0The script is pre‑loaded with SCRIPT LOAD and invoked via EVALSHA to save bandwidth.
Asynchronous Order Persistence via Redis Message Queue
After stock deduction, order data is pushed into a Redis list acting as a message queue: LPUSH orderList {order_content} The asynchronous worker consumes orders with: BRPOP orderList 0 This decouples order writing from the critical path, improving response time.
Data Control Module Synchronization
The data‑control module periodically syncs database data back to both master‑slave and read‑write split Redis instances, allowing more traffic to flow into the system when needed.
Conclusion
By combining CDN/browser caching, read‑write split Redis traffic filtering, atomic Lua‑based stock deduction, master‑slave Redis for fast inventory updates, and Redis‑based message queues for asynchronous order handling, a flash‑sale system can achieve high throughput, stability, and fairness under extreme concurrency.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Big Data Technology & Architecture
Wang Zhiwu, a big data expert, dedicated to sharing big data technology.
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.
