Background
In high-concurrency seckill (flash sale) scenarios, inventory deduction is the core bottleneck of the entire pipeline. Direct database operations cause severe row lock contention. This article covers how to use Redis + Lua for high-performance atomic inventory deduction.
The Problem with Traditional Approaches
The most straightforward approach executes SQL:
UPDATE stock SET count = count - 1
WHERE product_id = ? AND count > 0;
But in seckill scenarios, single-row hot updates cause severe lock contention, causing database CPU spikes and RT increases.
Redis Cache Preheating
Before the seckill event starts, preload inventory data into Redis:
public void warmUpStock(Long activityId) {
List<ProductStock> stocks = productStockMapper
.selectByActivityId(activityId);
for (ProductStock stock : stocks) {
String key = "seckill:stock:" + stock.getProductId();
redisTemplate.opsForValue().set(key, stock.getCount());
}
}
Lua Script for Atomic Operations
The core optimization: package inventory check + purchase limit check + stock deduction into a single Lua script executing atomically on Redis:
-- seckill.lua
local stockKey = KEYS[1]
local boughtKey = KEYS[2]
local userId = ARGV[1]
local limitPerUser = tonumber(ARGV[2])
local stock = tonumber(redis.call('get', stockKey) or '0')
if stock <= 0 then
return -1 -- out of stock
end
local bought = tonumber(redis.call('get', boughtKey .. ':' .. userId) or '0')
if bought >= limitPerUser then
return -2 -- purchase limit exceeded
end
redis.call('decr', stockKey)
redis.call('incr', boughtKey .. ':' .. userId)
return 1 -- success
Data Consistency Guarantees
- Idempotency:
requestId+ Redis Set prevents duplicate orders - Eventual Consistency: MQ consumer async order creation with retry + DLQ fallback
- Inventory Rollback: Order timeout cancellation triggers Lua-based stock replenishment
Performance Comparison
| Approach | QPS | Average RT |
|---|---|---|
| Direct DB | ~500 | 200ms+ |
| Redis + Lua | ~5000+ | <10ms |
Summary
The combination of Redis preheating + Lua atomic scripts + RabbitMQ async peak-shaving effectively handles high-concurrency seckill challenges. Lua scripts execute single-threaded on Redis server, naturally guaranteeing atomicity — the best practice for seckill inventory deduction.
Return to the blog index for more entries.