High‑Concurrency Flash‑Sale Blueprint: Redis Atomic Stock and Kafka Throttling

The article presents a production‑grade, scalable flash‑sale architecture that combines Redis atomic inventory deduction, Kafka asynchronous peak‑shaving, and careful database finalization, detailing each layer’s goals, pre‑filtering techniques, Lua scripting, idempotency, capacity planning, monitoring, and compensation strategies to prevent overselling and ensure reliability.

Cloud Architecture
Cloud Architecture
Cloud Architecture
High‑Concurrency Flash‑Sale Blueprint: Redis Atomic Stock and Kafka Throttling

Why a Flash‑Sale System Is Hard

Flash‑sale must handle extreme instantaneous concurrency (hundreds of thousands of QPS), a single hot skuId hotspot, zero tolerance for overselling, and response latency within a few hundred milliseconds.

Direct DB stock deduction causes row‑lock contention, CPU spikes, and connection‑pool exhaustion.

Using Redis as a universal source without eventual‑consistency handling leads to data loss.

Four‑Layer Goals for a Production‑Grade System

Business : no oversell, no duplicate orders, minimal loss, acceptable user experience.

Performance : interface P99 < 100 ms, entry layer 100 k–500 k QPS, order core path 5 k–20 k TPS.

Stability : graceful degradation, observable MQ backlog, compensation/recovery mechanisms.

Engineering : horizontal scalability, dynamic configuration switches, full‑chain monitoring and tracing.

Overall Architecture

The pipeline is: pre‑filter → Redis atomic stock → Kafka async peak‑shaving → final DB persistence , with idempotent compensation at each stage.

Flash‑sale architecture diagram
Flash‑sale architecture diagram

1. Pre‑Filtering (Front‑Door)

Static assets via CDN.

Dynamic‑static separation: only purchase, result query, and payment status remain dynamic.

CAPTCHA / sliding puzzle to block bots.

Flash‑sale token distribution before activity start; requests without a token are rejected.

User‑level pre‑checks (blacklist, region, membership level).

Gateway rate‑limiting per IP, per user, per interface.

Hot‑key isolation to avoid a single skuId throttling the whole cluster.

Rule of thumb: let 80 % of invalid requests fail at the gateway so Redis, Kafka, and MySQL are never touched.

2. Correct Flash‑Sale Interface (Four Steps)

Validate activity, user, token, and rate limits.

Execute a Redis Lua script that atomically checks stock, prevents duplicate purchase, decrements stock, records the buyer, stores a provisional order result, and creates a pre‑order record.

On success, send a Kafka message for asynchronous order creation.

Return a "queued" response instead of a synchronous order creation.

3. Why Redis Is the First Line of Defense

In‑memory access is extremely fast.

Lua scripts run single‑threaded, naturally serializing hotspot contention.

Read‑check‑write can be combined into one atomic script.

Redis keys used seckill:stock:{skuId} – remaining flash‑sale stock. seckill:buyers:{skuId} – set of users who have successfully grabbed the item. seckill:result:{userId}:{skuId} – per‑user purchase result. seckill:order:pre:{preOrderNo} – provisional order information. seckill:token:{token} – flash‑sale token for request validation.

Lua Script (Atomic Stock Deduction)

-- KEYS[1] = seckill:stock:{skuId}
-- KEYS[2] = seckill:buyers:{skuId}
-- KEYS[3] = seckill:result:{userId}:{skuId}
-- ARGV[1] = userId
-- ARGV[2] = preOrderNo
-- ARGV[3] = buyNum
-- return:
--   -1 duplicate order
--   -2 insufficient stock
--   1  success (queued)

local stock = tonumber(redis.call('GET', KEYS[1]))
if stock == nil or stock < tonumber(ARGV[3]) then
    return -2
end
if redis.call('SISMEMBER', KEYS[2], ARGV[1]) == 1 then
    return -1
end
redis.call('DECRBY', KEYS[1], ARGV[3])
redis.call('SADD', KEYS[2], ARGV[1])
redis.call('SET', KEYS[3], 'QUEUING', 'EX', 3600)
redis.call('HMSET', 'seckill:order:pre:'..ARGV[2],
    'userId', ARGV[1],
    'preOrderNo', ARGV[2],
    'status', 'QUEUING')
redis.call('EXPIRE', 'seckill:order:pre:'..ARGV[2], 3600)
return 1

Redis Stock Pre‑Heating Workflow

Write activity metadata to the DB after approval.

Minutes before start, run a pre‑heat job.

Load stock, per‑user limits, and start/end times from the DB.

Batch write to Redis and generate verification logs.

Read‑back a random sample for validation.

Open the activity entry via the configuration center.

Why Kafka Is the Second Line of Defense

Without a message queue the entry latency would explode from a few milliseconds to dozens or hundreds of milliseconds because the interface would have to perform order creation, price validation, DB stock deduction, coupon recording, and notification synchronously.

Kafka decouples the fast entry layer from the slower order‑processing layer, achieving classic peak‑shaving.

Kafka Topic Design

Topic name: seckill-order Partition key: skuId (preserves order per hot product) or userId (balances load when DB stock is the bottleneck).

Replication factor: at least 3.

Producer config: acks=all with idempotent producer.

Consumer config: manual offset commit.

Message Schema (Java)

public class SeckillOrderMessage {
    private String messageId;   // MQ deduplication
    private String preOrderNo;  // business idempotency key
    private Long activityId;    // activity tracing
    private Long skuId;
    private Long userId;
    private Integer quantity;
    private Long requestTime;
    private String traceId;    // cross‑service tracing
}

At‑Least‑Once Delivery and Idempotency

Kafka guarantees at‑least‑once delivery, so consumers must be idempotent. The order service checks the pre‑order number's uniqueness via a DB unique index and also performs a fast Redis check.

Database Role – Final Ledger

The database stores the final order, reconciles stock, and provides audit trails. It does not participate in the first‑wave competition.

Order Table Design

CREATE TABLE `seckill_order_00` (
  `id` BIGINT NOT NULL AUTO_INCREMENT,
  `order_no` VARCHAR(64) NOT NULL,
  `pre_order_no` VARCHAR(64) NOT NULL,
  `activity_id` BIGINT NOT NULL,
  `sku_id` BIGINT NOT NULL,
  `user_id` BIGINT NOT NULL,
  `amount` DECIMAL(10,2) NOT NULL,
  `status` TINYINT NOT NULL COMMENT '0‑pending 1‑paid 2‑canceled',
  `create_time` DATETIME NOT NULL,
  `update_time` DATETIME NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_pre_order_no` (`pre_order_no`),
  UNIQUE KEY `uk_user_activity` (`user_id`,`activity_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

The two unique constraints prevent duplicate orders and enforce per‑user activity limits.

Final Stock Deduction SQL (Optimistic Lock)

UPDATE product_stock
SET available_stock = available_stock - #{buyNum},
    version = version + 1
WHERE sku_id = #{skuId}
  AND available_stock >= #{buyNum}
  AND version = #{version};

If the update fails, the system distinguishes between genuine out‑of‑stock and optimistic‑lock conflict, applying retries or compensation accordingly.

Five Frequently Overlooked Production Points

Qualification ≠ Success : Redis success only guarantees a queue slot; the final order may still fail. Return "queued" messages to users.

Three‑Layer Idempotency : Interface, Redis, and DB each enforce duplicate‑order protection.

Hot‑Key Risk : A single hot skuId can saturate a Redis shard. Mitigate with sharding, local caches, and early sell‑out flags.

Message Backlog Is Normal : During the spike, Kafka lag will rise; design enough partitions and consumer instances, and monitor lag thresholds.

Compensation Determines Commercial Viability : Build a closed‑loop that scans stale "QUEUING" entries, checks Kafka consumption, verifies DB persistence, retries or rolls back, and generates manual audit lists for high‑risk cases.

Capacity Planning Example

Assume a peak of 100 k QPS, target entry latency 50 ms, and order service capacity 8 k TPS.

Gateway: 3000 QPS per instance → ~20 instances; with 30 % redundancy → 26–30 instances.

Kafka: after Redis success ~15 k TPS → 10–12 consumer instances, 16–32 partitions.

Engineering Practices

Stateless Services : All user state lives in Redis or DB; services can be scaled or restarted without loss.

Dynamic Configuration Center (Nacos, Apollo) for activity switches, rate‑limit thresholds, CAPTCHA toggles, MQ pause flags, and degradation controls.

Graceful Degradation : Auto‑close entry when MQ lag exceeds thresholds, return generic "activity busy" when Redis is unhealthy, pause real‑time DB queries if DB pressure spikes.

Observability : Prometheus metrics for gateway QPS, service latency, Redis hit rate, Kafka produce/consume TPS and lag, DB TPS and slow‑SQL, and result distribution (QUEUING/SUCCESS/FAIL/SOLD_OUT). Use TraceId propagation, structured logs, and SkyWalking/Zipkin for full‑chain tracing.

Typical Failure Scenarios & Remedies

Redis succeeds, Kafka fails : Immediately roll back Redis stock and user flag; if rollback fails, record the pre‑order in a compensation queue for later retry.

Kafka consumed, DB write times out : Do not commit the offset; let the consumer retry. DB unique index guarantees idempotent retries; after max retries, move to a dead‑letter queue.

User sees perpetual "queued" : Set a maximum QUEUING duration (e.g., 3 min). After timeout, query Kafka and DB; if no order exists, mark as FAIL.

Hot SKU overloads a Redis shard : Pre‑split hot stock into multiple buckets, enforce stricter gateway limits, and reject low‑priority users early.

Kafka lag continuously grows : Inspect lag per partition, scale consumer instances, and if necessary pause the flash‑sale entry until lag recovers.

End‑to‑End Real‑World Case Study

A mobile phone launch with 10 k stock, 5 M registered users, and a 300 k QPS peak applied the five‑layer pipeline, pre‑heated Redis 10 minutes before launch, issued tokens only to qualified users, and achieved:

Entry P99 latency 38 ms.

No oversell.

Duplicate orders blocked by Redis + DB unique index.

Kafka lag peaked at 90 seconds and then recovered.

Evolution Roadmap

Stage 1 – Small‑scale : Single monolith, Redis Lua, DB final write.

Stage 2 – Medium‑scale : Add gateway rate‑limit, Kafka async, separate order service.

Stage 3 – Large‑scale : Full static front‑end, Redis Cluster with hot‑key mitigation, multi‑partition Kafka, sharding, K8s auto‑scaling, full compensation platform.

The guiding principle: upgrade the layer that becomes the bottleneck.

Trade‑offs

Strong consistency is sacrificed for eventual consistency across Redis, Kafka, and DB.

Complexity rises: need idempotency, compensation, and reconciliation mechanisms.

Operational overhead increases: monitoring, alerting, and capacity planning become critical.

Summary

The essence of a flash‑sale system is not to process every request synchronously, but to attenuate traffic layer by layer: limit invalid traffic at the gateway, use Redis for fast atomic stock competition, Kafka to queue the surviving requests, and finally persist the order in a relational database with strong consistency. Proper idempotency, compensation loops, and observability are mandatory for production reliability.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

distributed systemsJavaRediskafkaHigh ConcurrencySpring BootFlash Sale
Cloud Architecture
Written by

Cloud Architecture

Focuses on cloud‑native and distributed architecture engineering, sharing practical solutions and lessons learned. Covers microservice governance, Kubernetes, observability, and stability engineering to help your systems run stable, fast, and cost‑effectively.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.