How to Build a High‑Concurrency Flash‑Sale System with Spring Boot, Redis, and Lua
The article analyzes why flash‑sale systems often crash under extreme traffic and presents a step‑by‑step solution using Spring Boot, Redis, and Lua that prevents overselling, pre‑warms stock, applies token‑bucket rate limiting, executes atomic stock deductions, and decouples order creation asynchronously while adding monitoring and safety measures.
Why Flash‑Sale Systems Fail
During major promotions (e.g., Double 11, 618) inventory can disappear before the page loads, requests may produce negative stock, and traffic spikes can overwhelm the database, causing system collapse. The root cause is that traditional e‑commerce architectures cannot sustain instantaneous extreme concurrency.
Flash‑sale essentials: fast (millisecond response), accurate (no oversell), stable (survive any load).
Technical Stack Choice
Why Redis?
In‑memory access speed.
Native support for atomic operations.
Horizontal scalability.
Acts as the first gate before the database.
Why Lua?
Single Redis command atomicity does not guarantee multi‑step business atomicity.
Lua scripts can combine check + decrement + validation into an indivisible operation.
Role of Spring Boot
Quick integration of Redis and message queue.
AOP, annotations, and auto‑configuration reduce complexity.
Facilitates building a standardized, maintainable flash‑sale service.
Overall Architecture
The core flow consists of:
Pre‑heat stock data into Redis before the event.
Apply token‑bucket rate limiting to filter invalid requests.
Execute a Lua script that atomically decrements stock.
On success, asynchronously create the order.
On failure, return quickly without blocking threads.
Compensate failures and trigger monitoring alerts.
Key Implementations
Stock Pre‑heat Service
package com.icoderoad.seckill.stock;</code>
<code>@Service</code>
<code>public class StockPreheatService {</code>
<code> @Autowired</code>
<code> private RedisTemplate<String, Object> redisTemplate;</code>
<code> @Autowired</code>
<code> private ProductRepository productRepository;</code>
<code> public void preheatStock(Long productId) {</code>
<code> Product product = productRepository.findById(productId);</code>
<code> redisTemplate.opsForValue().set("stock:" + productId, product.getStock(), Duration.ofHours(2));</code>
<code> redisTemplate.opsForValue().set("product:" + productId, product, Duration.ofHours(2));</code>
<code> redisTemplate.opsForValue().set("seckill:status:" + productId, "ready", Duration.ofHours(2));</code>
<code> }</code>
<code>}Core principle: the database does not participate in the main path before the flash‑sale starts.
Lua Script for Atomic Stock Deduction
package com.icoderoad.seckill.lua;</code>
<code>@Component</code>
<code>public class SeckillLuaScript {</code>
<code> private static final String SCRIPT =</code>
<code> "local stock = tonumber(redis.call('GET', KEYS[1]))
" +</code>
<code> "if not stock or stock <= 0 then return 0 end
" +</code>
<code> "redis.call('DECR', KEYS[1])
" +</code>
<code> "return 1";</code>
<code> @Autowired</code>
<code> private RedisTemplate<String, Object> redisTemplate;</code>
<code> public boolean execute(Long productId) {</code>
<code> RedisScript<Long> script = new DefaultRedisScript<>(SCRIPT, Long.class);</code>
<code> Long result = redisTemplate.execute(script, List.of("stock:" + productId));</code>
<code> return result != null && result == 1;</code>
<code> }</code>
<code>}Benefits: atomicity, zero lock contention, stability under high concurrency.
Traffic Shaping (Token‑Bucket Rate Limiting)
package com.icoderoad.seckill.limit;</code>
<code>@Component</code>
<code>public class TrafficShapingService {</code>
<code> private final Map<String, RateLimiter> limiterMap = new ConcurrentHashMap<>();</code>
<code> public boolean allow(String key) {</code>
<code> return limiterMap.computeIfAbsent(key, k -> RateLimiter.create(100)).tryAcquire();</code>
<code> }</code>
<code>}Rate limiting is not to reject users but to protect the system.
Flash‑Sale Core Service
package com.icoderoad.seckill.core;</code>
<code>@Service</code>
<code>public class SeckillService {</code>
<code> @Autowired private TrafficShapingService trafficService;</code>
<code> @Autowired private SeckillLuaScript luaScript;</code>
<code> @Autowired private OrderProducer orderProducer;</code>
<code> public SeckillResult seckill(Long productId, Long userId) {</code>
<code> if (!trafficService.allow("seckill:" + productId)) {</code>
<code> return SeckillResult.failure("系统繁忙");</code>
<code> }</code>
<code> if (!luaScript.execute(productId)) {</code>
<code> return SeckillResult.failure("库存不足");</code>
<code> }</code>
<code> orderProducer.send(productId, userId);
<code> return SeckillResult.success();</code>
<code> }</code>
<code>}Asynchronous Order Creation
package com.icoderoad.seckill.order;</code>
<code>@Component</code>
<code>public class OrderConsumer {</code>
<code> @RabbitListener(queues = "seckill.order.queue")</code>
<code> public void consume(OrderMessage msg) {</code>
<code> // create order</code>
<code> }</code>
<code>}Advanced Enhancements
Stock sharding to reduce Redis hotspot.
User‑level rate limiting.
Pre‑sale plus deposit model.
Anti‑scraping, duplicate‑request, and script‑attack protection.
Dynamic multi‑stage rate limiting.
Circuit breaking and degradation.
Metrics monitoring and alerting.
Performance & Security Configuration Example
spring:</code>
<code> redis:</code>
<code> lettuce:</code>
<code> pool:</code>
<code> max-active: 200</code>
<code> max-idle: 50</code>
<code> min-idle: 10</code>
<code> max-wait: 2000ms</code>
<code> timeout: 1000msSigned-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.
LuTiao Programming
LuTiao Programming is a friendly community offering free programming lessons. We inspire learners to explore new ideas and technologies and quickly acquire job-ready skills.
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.
