秒杀系统设计与实现

# 秒杀系统设计与实现

# 系统概述

秒杀系统是电商平台高并发场景下的典型应用,需要在短时间内处理大量用户请求,同时保证数据一致性和系统稳定性。本文档详细介绍秒杀系统的架构设计、核心技术方案以及性能优化策略。

# 系统架构设计

# 整体架构

秒杀系统架构
├── 前端层
│   ├── CDN加速
│   ├── 静态资源缓存
│   └── 防刷机制
├── 接入层
│   ├── 负载均衡
│   ├── 限流控制
│   └── 黑名单过滤
├── 应用层
│   ├── 秒杀活动管理
│   ├── 库存管理
│   ├── 订单处理
│   └── 支付处理
├── 缓存层
│   ├── Redis集群
│   ├── 本地缓存
│   └── 分布式锁
└── 数据层
    ├── 主从数据库
    ├── 分库分表
    └── 消息队列

# 核心实体设计

# 秒杀活动实体

@Entity
@Table(name = "flash_sale_activity")
public class FlashSaleActivity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "activity_name")
    private String activityName;
    
    @Column(name = "activity_desc")
    private String activityDesc;
    
    @Column(name = "start_time")
    private LocalDateTime startTime;
    
    @Column(name = "end_time")
    private LocalDateTime endTime;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "status")
    private ActivityStatus status;
    
    @Column(name = "create_time")
    private LocalDateTime createTime;
    
    @Column(name = "update_time")
    private LocalDateTime updateTime;
    
    // getters and setters
}

// 活动状态枚举
public enum ActivityStatus {
    PENDING("待开始"),
    RUNNING("进行中"),
    ENDED("已结束"),
    CANCELLED("已取消");
    
    private final String description;
    
    ActivityStatus(String description) {
        this.description = description;
    }
}

# 秒杀商品实体

@Entity
@Table(name = "flash_sale_item")
public class FlashSaleItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "activity_id")
    private Long activityId;
    
    @Column(name = "product_id")
    private Long productId;
    
    @Column(name = "product_name")
    private String productName;
    
    @Column(name = "original_price")
    private BigDecimal originalPrice;
    
    @Column(name = "flash_sale_price")
    private BigDecimal flashSalePrice;
    
    @Column(name = "total_stock")
    private Integer totalStock;
    
    @Column(name = "sold_count")
    private Integer soldCount;
    
    @Column(name = "limit_per_user")
    private Integer limitPerUser;
    
    @Column(name = "start_time")
    private LocalDateTime startTime;
    
    @Column(name = "end_time")
    private LocalDateTime endTime;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "status")
    private ItemStatus status;
    
    // getters and setters
}

// 商品状态枚举
public enum ItemStatus {
    PENDING("待开始"),
    RUNNING("秒杀中"),
    SOLD_OUT("已售罄"),
    ENDED("已结束");
    
    private final String description;
    
    ItemStatus(String description) {
        this.description = description;
    }
}

# 秒杀订单实体

@Entity
@Table(name = "flash_sale_order")
public class FlashSaleOrder {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "order_no")
    private String orderNo;
    
    @Column(name = "user_id")
    private Long userId;
    
    @Column(name = "activity_id")
    private Long activityId;
    
    @Column(name = "item_id")
    private Long itemId;
    
    @Column(name = "product_id")
    private Long productId;
    
    @Column(name = "quantity")
    private Integer quantity;
    
    @Column(name = "unit_price")
    private BigDecimal unitPrice;
    
    @Column(name = "total_amount")
    private BigDecimal totalAmount;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "status")
    private OrderStatus status;
    
    @Column(name = "create_time")
    private LocalDateTime createTime;
    
    @Column(name = "pay_time")
    private LocalDateTime payTime;
    
    @Column(name = "expire_time")
    private LocalDateTime expireTime;
    
    // getters and setters
}

// 订单状态枚举
public enum OrderStatus {
    PENDING_PAYMENT("待支付"),
    PAID("已支付"),
    CANCELLED("已取消"),
    EXPIRED("已过期");
    
    private final String description;
    
    OrderStatus(String description) {
        this.description = description;
    }
}

# 核心服务实现

# 秒杀活动服务

@Service
@Transactional
public class FlashSaleActivityService {
    
    @Autowired
    private FlashSaleActivityRepository activityRepository;
    
    @Autowired
    private FlashSaleItemRepository itemRepository;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    /**
     * 创建秒杀活动
     */
    public FlashSaleActivity createActivity(FlashSaleActivityCreateRequest request) {
        validateActivityRequest(request);
        
        FlashSaleActivity activity = new FlashSaleActivity();
        BeanUtils.copyProperties(request, activity);
        activity.setStatus(ActivityStatus.PENDING);
        activity.setCreateTime(LocalDateTime.now());
        
        return activityRepository.save(activity);
    }
    
    /**
     * 预热秒杀活动
     */
    @Async
    public void warmUpActivity(Long activityId) {
        FlashSaleActivity activity = getActivityById(activityId);
        List<FlashSaleItem> items = itemRepository.findByActivityId(activityId);
        
        // 预热活动信息到Redis
        String activityKey = "flash_sale:activity:" + activityId;
        redisTemplate.opsForValue().set(activityKey, activity, Duration.ofHours(24));
        
        // 预热商品信息和库存到Redis
        for (FlashSaleItem item : items) {
            String itemKey = "flash_sale:item:" + item.getId();
            redisTemplate.opsForValue().set(itemKey, item, Duration.ofHours(24));
            
            String stockKey = "flash_sale:stock:" + item.getId();
            redisTemplate.opsForValue().set(stockKey, item.getTotalStock());
        }
        
        log.info("秒杀活动预热完成, activityId: {}", activityId);
    }
    
    /**
     * 启动秒杀活动
     */
    @Scheduled(fixedRate = 60000) // 每分钟检查一次
    public void startPendingActivities() {
        LocalDateTime now = LocalDateTime.now();
        List<FlashSaleActivity> pendingActivities = activityRepository
            .findByStatusAndStartTimeLessThanEqual(ActivityStatus.PENDING, now);
        
        for (FlashSaleActivity activity : pendingActivities) {
            activity.setStatus(ActivityStatus.RUNNING);
            activityRepository.save(activity);
            
            // 更新商品状态
            List<FlashSaleItem> items = itemRepository.findByActivityId(activity.getId());
            items.forEach(item -> {
                item.setStatus(ItemStatus.RUNNING);
                itemRepository.save(item);
            });
            
            log.info("秒杀活动已启动, activityId: {}", activity.getId());
        }
    }
    
    /**
     * 结束秒杀活动
     */
    @Scheduled(fixedRate = 60000) // 每分钟检查一次
    public void endRunningActivities() {
        LocalDateTime now = LocalDateTime.now();
        List<FlashSaleActivity> runningActivities = activityRepository
            .findByStatusAndEndTimeLessThanEqual(ActivityStatus.RUNNING, now);
        
        for (FlashSaleActivity activity : runningActivities) {
            activity.setStatus(ActivityStatus.ENDED);
            activityRepository.save(activity);
            
            // 更新商品状态
            List<FlashSaleItem> items = itemRepository.findByActivityId(activity.getId());
            items.forEach(item -> {
                if (item.getStatus() == ItemStatus.RUNNING) {
                    item.setStatus(ItemStatus.ENDED);
                    itemRepository.save(item);
                }
            });
            
            log.info("秒杀活动已结束, activityId: {}", activity.getId());
        }
    }
}

# 秒杀服务核心实现

@Service
public class FlashSaleService {
    
    @Autowired
    private FlashSaleItemRepository itemRepository;
    
    @Autowired
    private FlashSaleOrderRepository orderRepository;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    @Autowired
    private RedissonClient redissonClient;
    
    /**
     * 秒杀抢购
     */
    public FlashSaleResult flashSale(FlashSaleRequest request) {
        Long itemId = request.getItemId();
        Long userId = request.getUserId();
        Integer quantity = request.getQuantity();
        
        // 1. 基础校验
        FlashSaleItem item = validateFlashSaleRequest(itemId, userId, quantity);
        
        // 2. 分布式锁控制并发
        String lockKey = "flash_sale_lock:" + itemId;
        RLock lock = redissonClient.getLock(lockKey);
        
        try {
            // 尝试获取锁,最多等待1秒,锁定10秒
            if (lock.tryLock(1, 10, TimeUnit.SECONDS)) {
                // 3. 再次检查库存(双重检查)
                if (!checkStock(itemId, quantity)) {
                    return FlashSaleResult.failure("商品已售罄");
                }
                
                // 4. 检查用户购买限制
                if (!checkUserPurchaseLimit(userId, itemId, quantity)) {
                    return FlashSaleResult.failure("超出购买限制");
                }
                
                // 5. 扣减库存
                boolean stockDecreased = decreaseStock(itemId, quantity);
                if (!stockDecreased) {
                    return FlashSaleResult.failure("库存不足");
                }
                
                // 6. 创建订单(异步处理)
                FlashSaleOrder order = createFlashSaleOrder(userId, item, quantity);
                
                // 7. 发送订单创建消息
                sendOrderCreatedMessage(order);
                
                return FlashSaleResult.success(order.getOrderNo());
                
            } else {
                return FlashSaleResult.failure("系统繁忙,请稍后重试");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return FlashSaleResult.failure("系统异常");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
    
    /**
     * 检查库存
     */
    private boolean checkStock(Long itemId, Integer quantity) {
        String stockKey = "flash_sale:stock:" + itemId;
        String currentStockStr = (String) redisTemplate.opsForValue().get(stockKey);
        
        if (currentStockStr == null) {
            return false;
        }
        
        int currentStock = Integer.parseInt(currentStockStr);
        return currentStock >= quantity;
    }
    
    /**
     * 扣减库存
     */
    private boolean decreaseStock(Long itemId, Integer quantity) {
        String stockKey = "flash_sale:stock:" + itemId;
        
        // 使用Lua脚本保证原子性
        String script = 
            "local current = redis.call('get', KEYS[1]) " +
            "if current and tonumber(current) >= tonumber(ARGV[1]) then " +
            "    return redis.call('decrby', KEYS[1], ARGV[1]) " +
            "else " +
            "    return -1 " +
            "end";
        
        Long result = redisTemplate.execute(
            new DefaultRedisScript<>(script, Long.class),
            Collections.singletonList(stockKey),
            quantity.toString()
        );
        
        return result != null && result >= 0;
    }
    
    /**
     * 检查用户购买限制
     */
    private boolean checkUserPurchaseLimit(Long userId, Long itemId, Integer quantity) {
        String userPurchaseKey = "flash_sale:user_purchase:" + itemId + ":" + userId;
        String purchasedStr = (String) redisTemplate.opsForValue().get(userPurchaseKey);
        
        int purchased = purchasedStr != null ? Integer.parseInt(purchasedStr) : 0;
        
        // 获取商品限购数量
        FlashSaleItem item = getItemFromCache(itemId);
        int limitPerUser = item.getLimitPerUser();
        
        return purchased + quantity <= limitPerUser;
    }
    
    /**
     * 创建秒杀订单
     */
    private FlashSaleOrder createFlashSaleOrder(Long userId, FlashSaleItem item, Integer quantity) {
        FlashSaleOrder order = new FlashSaleOrder();
        order.setOrderNo(generateOrderNo());
        order.setUserId(userId);
        order.setActivityId(item.getActivityId());
        order.setItemId(item.getId());
        order.setProductId(item.getProductId());
        order.setQuantity(quantity);
        order.setUnitPrice(item.getFlashSalePrice());
        order.setTotalAmount(item.getFlashSalePrice().multiply(BigDecimal.valueOf(quantity)));
        order.setStatus(OrderStatus.PENDING_PAYMENT);
        order.setCreateTime(LocalDateTime.now());
        order.setExpireTime(LocalDateTime.now().plusMinutes(15)); // 15分钟支付超时
        
        FlashSaleOrder savedOrder = orderRepository.save(order);
        
        // 更新用户购买记录
        updateUserPurchaseRecord(userId, item.getId(), quantity);
        
        return savedOrder;
    }
    
    /**
     * 更新用户购买记录
     */
    private void updateUserPurchaseRecord(Long userId, Long itemId, Integer quantity) {
        String userPurchaseKey = "flash_sale:user_purchase:" + itemId + ":" + userId;
        redisTemplate.opsForValue().increment(userPurchaseKey, quantity);
        redisTemplate.expire(userPurchaseKey, Duration.ofDays(1));
    }
    
    /**
     * 生成订单号
     */
    private String generateOrderNo() {
        return "FS" + System.currentTimeMillis() + RandomStringUtils.randomNumeric(6);
    }
}

# 限流和防刷服务

@Component
public class FlashSaleRateLimitService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    /**
     * 用户级别限流
     */
    public boolean checkUserRateLimit(Long userId, Long itemId) {
        String key = "rate_limit:user:" + userId + ":" + itemId;
        return checkRateLimit(key, 5, 60); // 每分钟最多5次请求
    }
    
    /**
     * IP级别限流
     */
    public boolean checkIpRateLimit(String ip, Long itemId) {
        String key = "rate_limit:ip:" + ip + ":" + itemId;
        return checkRateLimit(key, 100, 60); // 每分钟最多100次请求
    }
    
    /**
     * 全局限流
     */
    public boolean checkGlobalRateLimit(Long itemId) {
        String key = "rate_limit:global:" + itemId;
        return checkRateLimit(key, 10000, 1); // 每秒最多10000次请求
    }
    
    /**
     * 通用限流检查
     */
    private boolean checkRateLimit(String key, int limit, int windowSeconds) {
        String script = 
            "local current = redis.call('incr', KEYS[1]) " +
            "if current == 1 then " +
            "    redis.call('expire', KEYS[1], ARGV[2]) " +
            "end " +
            "return current <= tonumber(ARGV[1])";
        
        Boolean result = redisTemplate.execute(
            new DefaultRedisScript<>(script, Boolean.class),
            Collections.singletonList(key),
            String.valueOf(limit),
            String.valueOf(windowSeconds)
        );
        
        return Boolean.TRUE.equals(result);
    }
    
    /**
     * 检查用户是否在黑名单中
     */
    public boolean isUserBlacklisted(Long userId) {
        String key = "blacklist:user:" + userId;
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }
    
    /**
     * 将用户加入黑名单
     */
    public void addUserToBlacklist(Long userId, Duration duration) {
        String key = "blacklist:user:" + userId;
        redisTemplate.opsForValue().set(key, "1", duration);
    }
}

# 消息队列处理

# 订单处理消息

@Component
public class FlashSaleOrderProcessor {
    
    @Autowired
    private FlashSaleOrderRepository orderRepository;
    
    @Autowired
    private InventoryService inventoryService;
    
    /**
     * 处理订单创建消息
     */
    @RabbitListener(queues = "flash.sale.order.created")
    public void handleOrderCreated(FlashSaleOrderMessage message) {
        try {
            Long orderId = message.getOrderId();
            FlashSaleOrder order = orderRepository.findById(orderId)
                .orElseThrow(() -> new BusinessException("订单不存在"));
            
            // 扣减真实库存
            boolean success = inventoryService.decreaseStock(
                order.getProductId(), 
                order.getQuantity()
            );
            
            if (!success) {
                // 库存扣减失败,取消订单并回滚Redis库存
                cancelOrderAndRollbackStock(order);
            } else {
                log.info("订单库存扣减成功, orderNo: {}", order.getOrderNo());
            }
            
        } catch (Exception e) {
            log.error("处理订单创建消息失败", e);
            // 可以考虑重试或者人工处理
        }
    }
    
    /**
     * 处理订单支付超时
     */
    @RabbitListener(queues = "flash.sale.order.timeout")
    public void handleOrderTimeout(FlashSaleOrderMessage message) {
        try {
            Long orderId = message.getOrderId();
            FlashSaleOrder order = orderRepository.findById(orderId)
                .orElse(null);
            
            if (order != null && order.getStatus() == OrderStatus.PENDING_PAYMENT) {
                // 取消订单
                order.setStatus(OrderStatus.EXPIRED);
                orderRepository.save(order);
                
                // 回滚库存
                rollbackStock(order);
                
                log.info("订单支付超时已处理, orderNo: {}", order.getOrderNo());
            }
            
        } catch (Exception e) {
            log.error("处理订单超时消息失败", e);
        }
    }
    
    /**
     * 回滚库存
     */
    private void rollbackStock(FlashSaleOrder order) {
        // 回滚Redis库存
        String stockKey = "flash_sale:stock:" + order.getItemId();
        redisTemplate.opsForValue().increment(stockKey, order.getQuantity());
        
        // 回滚真实库存
        inventoryService.increaseStock(order.getProductId(), order.getQuantity());
        
        // 回滚用户购买记录
        String userPurchaseKey = "flash_sale:user_purchase:" + order.getItemId() + ":" + order.getUserId();
        redisTemplate.opsForValue().increment(userPurchaseKey, -order.getQuantity());
    }
}

# 数据库设计

# 秒杀活动表

CREATE TABLE `flash_sale_activity` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `activity_name` varchar(100) NOT NULL COMMENT '活动名称',
  `activity_desc` varchar(500) DEFAULT NULL COMMENT '活动描述',
  `start_time` datetime NOT NULL COMMENT '开始时间',
  `end_time` datetime NOT NULL COMMENT '结束时间',
  `status` varchar(20) NOT NULL DEFAULT 'PENDING' COMMENT '状态',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_status_time` (`status`, `start_time`, `end_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='秒杀活动表';

# 秒杀商品表

CREATE TABLE `flash_sale_item` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `activity_id` bigint NOT NULL COMMENT '活动ID',
  `product_id` bigint NOT NULL COMMENT '商品ID',
  `product_name` varchar(200) NOT NULL COMMENT '商品名称',
  `original_price` decimal(10,2) NOT NULL COMMENT '原价',
  `flash_sale_price` decimal(10,2) NOT NULL COMMENT '秒杀价',
  `total_stock` int NOT NULL COMMENT '总库存',
  `sold_count` int NOT NULL DEFAULT '0' COMMENT '已售数量',
  `limit_per_user` int NOT NULL DEFAULT '1' COMMENT '每人限购数量',
  `start_time` datetime NOT NULL COMMENT '开始时间',
  `end_time` datetime NOT NULL COMMENT '结束时间',
  `status` varchar(20) NOT NULL DEFAULT 'PENDING' COMMENT '状态',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_activity_id` (`activity_id`),
  KEY `idx_product_id` (`product_id`),
  KEY `idx_status_time` (`status`, `start_time`, `end_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='秒杀商品表';

# 秒杀订单表

CREATE TABLE `flash_sale_order` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `order_no` varchar(50) NOT NULL COMMENT '订单号',
  `user_id` bigint NOT NULL COMMENT '用户ID',
  `activity_id` bigint NOT NULL COMMENT '活动ID',
  `item_id` bigint NOT NULL COMMENT '商品ID',
  `product_id` bigint NOT NULL COMMENT '商品ID',
  `quantity` int NOT NULL COMMENT '购买数量',
  `unit_price` decimal(10,2) NOT NULL COMMENT '单价',
  `total_amount` decimal(10,2) NOT NULL COMMENT '总金额',
  `status` varchar(20) NOT NULL DEFAULT 'PENDING_PAYMENT' COMMENT '状态',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `pay_time` datetime DEFAULT NULL COMMENT '支付时间',
  `expire_time` datetime NOT NULL COMMENT '过期时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_order_no` (`order_no`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_activity_item` (`activity_id`, `item_id`),
  KEY `idx_status_expire` (`status`, `expire_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='秒杀订单表';

# 性能优化策略

# 1. 多级缓存

@Component
public class FlashSaleCacheService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    // 本地缓存
    private final Cache<String, Object> localCache = Caffeine.newBuilder()
        .maximumSize(1000)
        .expireAfterWrite(Duration.ofMinutes(5))
        .build();
    
    /**
     * 多级缓存获取
     */
    public <T> T get(String key, Class<T> type, Supplier<T> dataLoader) {
        // 1. 先查本地缓存
        T value = (T) localCache.getIfPresent(key);
        if (value != null) {
            return value;
        }
        
        // 2. 查Redis缓存
        value = (T) redisTemplate.opsForValue().get(key);
        if (value != null) {
            localCache.put(key, value);
            return value;
        }
        
        // 3. 查数据库
        value = dataLoader.get();
        if (value != null) {
            redisTemplate.opsForValue().set(key, value, Duration.ofHours(1));
            localCache.put(key, value);
        }
        
        return value;
    }
}

# 2. 异步处理

@Configuration
@EnableAsync
public class AsyncConfig {
    
    @Bean("flashSaleExecutor")
    public Executor flashSaleExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(50);
        executor.setQueueCapacity(1000);
        executor.setThreadNamePrefix("FlashSale-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

# 3. 数据库优化

-- 读写分离配置
-- 主库用于写操作,从库用于读操作

-- 分库分表策略
-- 按用户ID分表
CREATE TABLE `flash_sale_order_0` LIKE `flash_sale_order`;
CREATE TABLE `flash_sale_order_1` LIKE `flash_sale_order`;
-- ... 更多分表

-- 索引优化
CREATE INDEX idx_user_activity_item ON flash_sale_order(user_id, activity_id, item_id);
CREATE INDEX idx_create_time ON flash_sale_order(create_time);

# 监控和告警

# 关键指标监控

@Component
public class FlashSaleMonitorService {
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    /**
     * 记录秒杀请求量
     */
    public void recordFlashSaleRequest(Long itemId, String result) {
        Counter.builder("flash_sale_requests")
            .tag("item_id", String.valueOf(itemId))
            .tag("result", result)
            .register(meterRegistry)
            .increment();
    }
    
    /**
     * 记录响应时间
     */
    public void recordResponseTime(Long itemId, long duration) {
        Timer.builder("flash_sale_response_time")
            .tag("item_id", String.valueOf(itemId))
            .register(meterRegistry)
            .record(duration, TimeUnit.MILLISECONDS);
    }
    
    /**
     * 记录库存变化
     */
    public void recordStockChange(Long itemId, int stock) {
        Gauge.builder("flash_sale_stock")
            .tag("item_id", String.valueOf(itemId))
            .register(meterRegistry, stock, Number::doubleValue);
    }
}

# 总结

秒杀系统的核心设计要点:

  1. 高并发处理:多级缓存、分布式锁、异步处理
  2. 库存控制:Redis原子操作、数据库最终一致性
  3. 限流防刷:多维度限流、黑名单机制
  4. 性能优化:缓存预热、读写分离、分库分表
  5. 监控告警:实时监控关键指标、异常告警
  6. 容错处理:降级策略、熔断机制、补偿事务

通过以上设计,可以构建一个高性能、高可用的秒杀系统,能够应对大流量冲击并保证数据一致性。