Implementing a High-Performance Flash Sale System with Redis

Generating Distributed Unique Identifiers with Redis

In high-concurrency flash sale scenarios, traditional database auto-increment primary keys present several critical limitations that can compromise system integrity and performance.

Limitations of Database Auto-Increment IDs

When processing time-sensitive orders during promotional events, relying on database-generated sequential identifiers introduces two major concerns:

  • Predictability: Sequential IDs expose business metrics such as order volume and growth patterns to competitors
  • Scalability Bottleneck: Single-table auto-increment mechanisms create performance ceilings and hotspot issues in distributde architectures

Redis-Powered Distributed ID Generator

A robust solution employs Redis atomic operations combined with bitwise composition to generate 64-bit unique identifiers with temporal ordering capabilities.

The identifier structure consists of:

  • Sign Bit (1 bit): Permanently set to 0 for future compatibility
  • Timestamp Component (31 bits): Stores seconds elapsed since custom epoch, providing approximately 69 years of range (2³¹ seconds)
  • Sequence Counter (32 bits): Tracks increments within the same second, supporting over 4 billion unique IDs per second
@Component
public class RedisDistributedIdGenerator {
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    // Custom epoch: January 1, 2022 00:00:00 UTC
    private static final long EPOCH_START = 1640995200L;
    private static final long SEQUENCE_BIT_LENGTH = 32L;
    
    public long generateId(String businessKey) {
        // Capture current timestamp
        LocalDateTime currentTime = LocalDateTime.now(ZoneOffset.UTC);
        long currentSecond = currentTime.toEpochSecond(ZoneOffset.UTC);
        long timestampOffset = currentSecond - EPOCH_START;
        
        // Generate atomic sequence number using Redis
        String dateKey = currentTime.format(DateTimeFormatter.BASIC_ISO_DATE);
        String counterKey = String.format("id:counter:%s:%s", businessKey, dateKey);
        Long sequence = redisTemplate.opsForValue().increment(counterKey);
        
        // Compose final ID: timestamp << 32 | sequence
        return timestampOffset << SEQUENCE_BIT_LENGTH | sequence;
    }
}

Building Overselling Protection for Flash Sales

The Race Condition Challenge

During peak traffic, thousands of concurrent requests may simultaneously query inventory levels before deduction. This check-then-act pattern creates a critical race window where multiple threads can oversell limited stock.

Optimistic Locking Strategy

The initial approach uses version comparison—ensuring the stock value hasn't changed between read and write operations:

// Initial flawed implementation
boolean deductionSuccess = couponService.update()
    .setSql("available_quantity = available_quantity - 1")
    .eq("coupon_id", couponId)
    .eq("available_quantity", currentStock) // Version check
    .update();

if (!deductionSuccess) {
    return ApiResponse.error("Insufficient inventory");
}

This implementation suffers from high abort rates because all concurrent threads read the same stock value, but only one can successfully update it. The remaining transcations fail despite inventory still being available.

Enhanced Condition-Based Update

A more pragmatic approach eliminates the version comparison and simply verifies that inventory remains positive:

// Improved implementation
boolean updateSuccess = couponService.update()
    .setSql("stock = stock - 1")
    .eq("promotion_id", promoId)
    .gt("stock", 0) // Ensure stock remains positive
    .update();

if (!updateSuccess) {
    return Result.failure("Inventory depleted");
}

This pattern allows all qualified requests to proceed as long as inventory exists, dramatically improving success rates while maintaining data consistency through atomic database operations.

Tags: Redis distributed-ids flash-sale optimistic-locking spring-data-redis

Posted on Thu, 13 Aug 2026 16:13:29 +0000 by raven_web