如何设计10万QPS秒杀系统?缓存+消息队列+分布式锁架构实战

如何设计10万QPS秒杀系统?缓存+消息队列+分布式锁架构实战

Scroll Down

如何设计10万QPS秒杀系统?缓存+消息队列+分布式锁架构实战

🚀 极客小贴士

💡 你知道吗?

想象一下,如果100万人同时冲进一家只有1000个座位的电影院,会发生什么?要么门被挤坏,要么系统崩溃!这就是为什么高并发系统需要"智能排队"、"快速通道"和"安全门禁"的原因!


🎯 从"双11抢购"看高并发架构

还记得去年双11,你熬夜抢iPhone 16 Pro Max的场景吗?零点一到,手指疯狂点击"立即购买",结果页面卡死,刷新后显示"商品已售罄"…

这种"秒杀"场景,就是高并发架构设计的经典案例。今天我们就来聊聊,如何让100万人同时抢购1000台手机,系统还能稳稳当当不崩溃。

📱 项目背景

假设你正在开发一个双11秒杀系统,需要处理以下挑战:

用户量:100万+ 同时在线(相当于一个小城市的人口)
商品:iPhone 16 Pro Max,库存1000台(僧多粥少)
时间:11月11日 00:00:00 准时开抢(生死时速)
要求:系统不能崩溃,用户体验要流畅(不能让大家白熬夜)

🐌 传统架构:像"单通道收费站"

如果使用传统的单体架构,就像在高速公路上只开一个收费通道,会出现什么情况?

// 传统架构的问题代码示例
@RestController
public class SeckillController {

    @Autowired
    private ProductService productService;

    @PostMapping("/seckill")
    public Result seckill(@RequestParam Long productId, @RequestParam Long userId) {
        // 1. 查询商品库存(数据库查询)
        Product product = productService.getById(productId);
        if (product.getStock() <= 0) {
            return Result.error("商品已售罄");
        }

        // 2. 扣减库存(数据库更新)
        boolean success = productService.reduceStock(productId);
        if (!success) {
            return Result.error("库存不足");
        }

        // 3. 创建订单(数据库插入)
        Order order = new Order();
        order.setProductId(productId);
        order.setUserId(userId);
        orderService.createOrder(order);

        return Result.success("秒杀成功");
    }
}

问题分析

  • 数据库瓶颈:100万请求同时查询数据库,就像100万人同时问一个服务员"还有座位吗?",服务员直接累趴下
  • 超卖问题:多个线程同时扣减库存,可能出现"卖了1001台手机,但实际只有1000台"的尴尬
  • 响应缓慢:每个请求都要等待数据库操作,用户等得花儿都谢了
  • 系统雪崩:一个服务崩溃,整个系统就像多米诺骨牌一样倒下

🚀 高并发架构:像"智能交通系统"

使用高并发架构设计,就像把单通道收费站升级为智能交通系统:

// 高并发架构解决方案
@RestController
public class SeckillController {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostMapping("/seckill")
    public Result seckill(@RequestParam Long productId, @RequestParam Long userId) {
        // 1. 分布式锁防止重复提交
        String lockKey = "seckill:lock:" + userId + ":" + productId;
        Boolean lockAcquired = redisTemplate.opsForValue()
                .setIfAbsent(lockKey, "1", Duration.ofSeconds(30));

        if (!lockAcquired) {
            return Result.error("请勿重复提交");
        }

        try {
            // 2. 从Redis缓存检查库存
            String stockKey = "seckill:stock:" + productId;
            Long stock = redisTemplate.opsForValue().decrement(stockKey);

            if (stock < 0) {
                // 库存不足,回滚
                redisTemplate.opsForValue().increment(stockKey);
                return Result.error("商品已售罄");
            }

            // 3. 异步处理订单(消息队列)
            SeckillMessage message = new SeckillMessage();
            message.setProductId(productId);
            message.setUserId(userId);
            message.setTimestamp(System.currentTimeMillis());

            rabbitTemplate.convertAndSend("seckill.exchange", "seckill.order", message);

            return Result.success("秒杀成功,订单处理中...");

        } finally {
            // 4. 释放分布式锁
            redisTemplate.delete(lockKey);
        }
    }
}

优势分析

  • 缓存加速:Redis缓存库存信息,就像给服务员配了个"智能助手",查询速度提升1000倍
  • 异步处理:消息队列异步处理订单,就像"先拿号,后取餐",响应时间从2秒降到50ms
  • 分布式锁:防止重复提交和超卖问题,就像"一人一票"的入场券
  • 系统解耦:各个服务独立部署,互不影响,就像"各司其职"的专业团队

1. 高并发系统设计原则:从"银行管理"学架构

1.1 CAP理论:分布式系统的"三难选择"

想象一下,你开了一家银行,有三个要求:

  • 一致性:所有分行的账本必须完全一致
  • 可用性:客户随时都能存取款
  • 分区容错性:即使网络断了,银行还能正常营业

CAP理论告诉我们:这三个要求不能同时满足,就像"鱼和熊掌不可兼得"。

TypeError: undefined is not an object (evaluating 't.v')

实际应用场景

// CP系统示例:强一致性要求(像银行转账)
@Service
public class BankAccountService {

    // 银行转账必须保证强一致性,宁可慢一点也不能出错
    @Transactional
    public void transfer(Long fromAccount, Long toAccount, BigDecimal amount) {
        // 必须保证数据一致性,可以牺牲可用性
        Account from = accountRepository.findById(fromAccount);
        Account to = accountRepository.findById(toAccount);

        if (from.getBalance().compareTo(amount) < 0) {
            throw new InsufficientFundsException("余额不足");
        }

        from.setBalance(from.getBalance().subtract(amount));
        to.setBalance(to.getBalance().add(amount));

        accountRepository.save(from);
        accountRepository.save(to);
    }
}

// AP系统示例:高可用性要求(像社交媒体)
@Service
public class UserProfileService {

    // 用户资料可以最终一致性,但必须高可用(宁可看到旧数据也不能卡死)
    public UserProfile getUserProfile(Long userId) {
        // 优先从缓存获取,保证高可用
        UserProfile profile = redisTemplate.opsForValue().get("user:profile:" + userId);
        if (profile == null) {
            // 缓存未命中,从数据库获取
            profile = userRepository.findById(userId);
            redisTemplate.opsForValue().set("user:profile:" + userId, profile, Duration.ofHours(1));
        }
        return profile;
    }
}

1.2 BASE理论:最终一致性(像"外卖配送")

BASE理论是对CAP理论的补充,强调最终一致性,就像外卖配送:

  • BA (Basically Available):基本可用(餐厅还在营业,能接单)
  • S (Soft State):软状态(订单状态:已下单→制作中→配送中→已送达)
  • E (Eventually Consistent):最终一致性(最终你一定能收到外卖)
// BASE理论实践:最终一致性(像外卖订单处理)
@Service
public class OrderService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void createOrder(Order order) {
        // 1. 立即返回成功(基本可用)- 就像外卖平台立即给你订单号
        order.setStatus(OrderStatus.PROCESSING);
        orderRepository.save(order);

        // 2. 异步处理(软状态)- 订单状态会不断变化
        OrderProcessMessage message = new OrderProcessMessage();
        message.setOrderId(order.getId());
        message.setTimestamp(System.currentTimeMillis());

        rabbitTemplate.convertAndSend("order.exchange", "order.process", message);

        // 3. 最终一致性:通过消息队列保证数据最终一致(最终订单一定会完成)
    }

    @RabbitListener(queues = "order.process.queue")
    public void processOrder(OrderProcessMessage message) {
        try {
            // 异步处理订单逻辑
            Order order = orderRepository.findById(message.getOrderId());

            // 库存扣减
            inventoryService.reduceStock(order.getProductId(), order.getQuantity());

            // 支付处理
            paymentService.processPayment(order);

            // 更新订单状态
            order.setStatus(OrderStatus.COMPLETED);
            orderRepository.save(order);

        } catch (Exception e) {
            // 处理失败,记录日志,后续重试
            log.error("订单处理失败: {}", message.getOrderId(), e);
        }
    }
}

2. 多级缓存架构设计:像"城市交通系统"

2.1 缓存架构层次

多级缓存架构就像城市交通系统,从高速公路到小区道路,层层递进,让数据"跑"得更快:

TypeError: undefined is not an object (evaluating 't.v')

2.2 本地缓存实现:像"办公桌上的便签"

// 本地缓存实现:Caffeine(像办公桌上的便签,随手就能拿到)
@Configuration
public class CacheConfig {

    @Bean
    public Cache<String, Object> localCache() {
        return Caffeine.newBuilder()
                .maximumSize(10000)                    // 最大缓存数量(便签本最多10000张)
                .expireAfterWrite(Duration.ofMinutes(5)) // 写入后5分钟过期(便签5分钟后自动撕掉)
                .expireAfterAccess(Duration.ofMinutes(2)) // 访问后2分钟过期(不看就撕掉)
                .recordStats()                         // 开启统计(记录使用情况)
                .build();
    }
}

@Service
public class ProductService {

    @Autowired
    private Cache<String, Object> localCache;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private ProductRepository productRepository;

    public Product getProduct(Long productId) {
        String cacheKey = "product:" + productId;

        // 1. 先从本地缓存获取(先看办公桌上的便签)
        Product product = (Product) localCache.getIfPresent(cacheKey);
        if (product != null) {
            log.info("从本地缓存获取商品: {}(便签上找到了!)", productId);
            return product;
        }

        // 2. 本地缓存未命中,从Redis获取(便签没有,去文件柜找)
        product = (Product) redisTemplate.opsForValue().get(cacheKey);
        if (product != null) {
            log.info("从Redis缓存获取商品: {}(文件柜里找到了!)", productId);
            // 回填本地缓存(抄一份放到便签上)
            localCache.put(cacheKey, product);
            return product;
        }

        // 3. Redis缓存未命中,从数据库获取(文件柜也没有,去档案室找)
        product = productRepository.findById(productId);
        if (product != null) {
            log.info("从数据库获取商品: {}(档案室里找到了!)", productId);
            // 回填Redis缓存(复印一份放到文件柜)
            redisTemplate.opsForValue().set(cacheKey, product, Duration.ofHours(1));
            // 回填本地缓存(再抄一份放到便签上)
            localCache.put(cacheKey, product);
        }

        return product;
    }
}

2.3 缓存一致性策略

// 缓存一致性策略:Cache-Aside模式
@Service
public class ProductService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private ProductRepository productRepository;

    public void updateProduct(Product product) {
        // 1. 先更新数据库
        productRepository.save(product);

        // 2. 删除缓存(让下次查询时重新加载)
        String cacheKey = "product:" + product.getId();
        redisTemplate.delete(cacheKey);

        // 3. 可选:异步更新缓存
        CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(100); // 等待数据库事务提交
                redisTemplate.opsForValue().set(cacheKey, product, Duration.ofHours(1));
            } catch (Exception e) {
                log.error("异步更新缓存失败", e);
            }
        });
    }

    // 缓存预热:系统启动时预加载热点数据
    @PostConstruct
    public void warmUpCache() {
        List<Product> hotProducts = productRepository.findHotProducts();
        for (Product product : hotProducts) {
            String cacheKey = "product:" + product.getId();
            redisTemplate.opsForValue().set(cacheKey, product, Duration.ofHours(1));
        }
        log.info("缓存预热完成,预加载{}个商品", hotProducts.size());
    }
}

3. 消息队列架构设计:像"智能邮局系统"

3.1 消息队列的作用

消息队列就像智能邮局系统,解决了以下问题:

  • 解耦:服务之间不直接调用,通过消息通信(就像写信,不用面对面)
  • 削峰:将突发流量平滑处理(就像邮局分时段处理邮件,避免拥堵)
  • 异步:提高系统响应速度(就像"先投递,后处理")
  • 可靠性:消息持久化,确保不丢失(就像挂号信,有回执保证)
TypeError: undefined is not an object (evaluating 't.v')

3.2 RabbitMQ实战配置

// RabbitMQ配置
@Configuration
@EnableRabbit
public class RabbitMQConfig {

    // 秒杀交换机
    @Bean
    public TopicExchange seckillExchange() {
        return new TopicExchange("seckill.exchange", true, false);
    }

    // 秒杀订单队列
    @Bean
    public Queue seckillOrderQueue() {
        return QueueBuilder.durable("seckill.order.queue")
                .withArgument("x-message-ttl", 300000) // 5分钟TTL
                .withArgument("x-dead-letter-exchange", "seckill.dlx.exchange")
                .withArgument("x-dead-letter-routing-key", "seckill.order.failed")
                .build();
    }

    // 绑定关系
    @Bean
    public Binding seckillOrderBinding() {
        return BindingBuilder.bind(seckillOrderQueue())
                .to(seckillExchange())
                .with("seckill.order");
    }

    // 死信交换机
    @Bean
    public TopicExchange seckillDlxExchange() {
        return new TopicExchange("seckill.dlx.exchange", true, false);
    }

    // 死信队列
    @Bean
    public Queue seckillDlxQueue() {
        return QueueBuilder.durable("seckill.dlx.queue").build();
    }

    @Bean
    public Binding seckillDlxBinding() {
        return BindingBuilder.bind(seckillDlxQueue())
                .to(seckillDlxExchange())
                .with("seckill.order.failed");
    }
}

3.3 消息生产者实现

// 消息生产者
@Service
public class SeckillMessageProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendSeckillMessage(SeckillMessage message) {
        try {
            // 设置消息属性
            MessageProperties properties = new MessageProperties();
            properties.setDeliveryMode(MessageDeliveryMode.PERSISTENT); // 持久化
            properties.setExpiration("300000"); // 5分钟过期

            Message rabbitMessage = new Message(JSON.toJSONBytes(message), properties);

            // 发送消息
            rabbitTemplate.send("seckill.exchange", "seckill.order", rabbitMessage);

            log.info("秒杀消息发送成功: userId={}, productId={}",
                    message.getUserId(), message.getProductId());

        } catch (Exception e) {
            log.error("秒杀消息发送失败", e);
            throw new RuntimeException("消息发送失败", e);
        }
    }
}

// 消息对象
@Data
public class SeckillMessage {
    private Long userId;
    private Long productId;
    private Long timestamp;
    private String requestId; // 用于幂等性控制
}

3.4 消息消费者实现

// 消息消费者
@Component
public class SeckillMessageConsumer {

    @Autowired
    private OrderService orderService;

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    private PaymentService paymentService;

    @RabbitListener(queues = "seckill.order.queue")
    public void handleSeckillMessage(SeckillMessage message, Channel channel,
                                     @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        try {
            log.info("开始处理秒杀消息: userId={}, productId={}",
                    message.getUserId(), message.getProductId());

            // 1. 幂等性检查
            if (orderService.isOrderExists(message.getUserId(), message.getProductId())) {
                log.info("订单已存在,跳过处理: userId={}, productId={}",
                        message.getUserId(), message.getProductId());
                channel.basicAck(deliveryTag, false);
                return;
            }

            // 2. 创建订单
            Order order = orderService.createOrder(message.getUserId(), message.getProductId());

            // 3. 扣减库存
            boolean stockReduced = inventoryService.reduceStock(message.getProductId(), 1);
            if (!stockReduced) {
                log.error("库存扣减失败: productId={}", message.getProductId());
                channel.basicNack(deliveryTag, false, true); // 重新入队
                return;
            }

            // 4. 处理支付
            boolean paymentSuccess = paymentService.processPayment(order);
            if (!paymentSuccess) {
                log.error("支付处理失败: orderId={}", order.getId());
                // 回滚库存
                inventoryService.rollbackStock(message.getProductId(), 1);
                channel.basicNack(deliveryTag, false, true);
                return;
            }

            // 5. 更新订单状态
            order.setStatus(OrderStatus.COMPLETED);
            orderService.updateOrder(order);

            log.info("秒杀消息处理成功: orderId={}", order.getId());
            channel.basicAck(deliveryTag, false);

        } catch (Exception e) {
            log.error("秒杀消息处理失败", e);
            try {
                // 处理失败,拒绝消息并重新入队
                channel.basicNack(deliveryTag, false, true);
            } catch (IOException ioException) {
                log.error("消息拒绝失败", ioException);
            }
        }
    }

    // 死信队列处理
    @RabbitListener(queues = "seckill.dlx.queue")
    public void handleFailedMessage(SeckillMessage message) {
        log.error("秒杀消息处理失败,进入死信队列: userId={}, productId={}",
                message.getUserId(), message.getProductId());

        // 可以在这里进行补偿操作,比如发送通知、记录日志等
        notificationService.sendFailedNotification(message);
    }
}

4. 分布式锁架构设计:像"银行金库的钥匙管理"

4.1 分布式锁的实现方案对比

分布式锁就像银行金库的钥匙管理,确保同一时间只有一个"钥匙持有者",防止"多人同时开锁"的混乱:

实现方案 优点 缺点 适用场景 生活比喻
Redis 性能高、实现简单 单点故障、数据丢失 高并发、对一致性要求不高 像"智能门锁",快但可能故障
Zookeeper 强一致性、可靠性高 性能较低、实现复杂 对一致性要求高 像"银行金库锁",安全但慢
数据库 实现简单、可靠性高 性能低、容易死锁 并发量不大、简单场景 像"传统门锁",简单但容易卡住
TypeError: undefined is not an object (evaluating 't.v')

4.2 Redis分布式锁实现

// Redis分布式锁实现
@Component
public class RedisDistributedLock {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String LOCK_PREFIX = "lock:";
    private static final String UNLOCK_SCRIPT =
            "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                    "return redis.call('del', KEYS[1]) " +
                    "else return 0 end";

    /**
     * 获取分布式锁
     * @param lockKey 锁的key
     * @param requestId 请求ID,用于标识锁的持有者
     * @param expireTime 过期时间(毫秒)
     * @return 是否获取成功
     */
    public boolean tryLock(String lockKey, String requestId, long expireTime) {
        String key = LOCK_PREFIX + lockKey;

        Boolean success = redisTemplate.opsForValue()
                .setIfAbsent(key, requestId, Duration.ofMillis(expireTime));

        return Boolean.TRUE.equals(success);
    }

    /**
     * 释放分布式锁
     * @param lockKey 锁的key
     * @param requestId 请求ID
     * @return 是否释放成功
     */
    public boolean unlock(String lockKey, String requestId) {
        String key = LOCK_PREFIX + lockKey;

        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setScriptText(UNLOCK_SCRIPT);
        script.setResultType(Long.class);

        Long result = redisTemplate.execute(script,
                Collections.singletonList(key), requestId);

        return result != null && result == 1L;
    }

    /**
     * 带重试的锁获取
     * @param lockKey 锁的key
     * @param requestId 请求ID
     * @param expireTime 过期时间
     * @param retryTimes 重试次数
     * @param retryInterval 重试间隔(毫秒)
     * @return 是否获取成功
     */
    public boolean tryLockWithRetry(String lockKey, String requestId,
                                    long expireTime, int retryTimes, long retryInterval) {
        for (int i = 0; i < retryTimes; i++) {
            if (tryLock(lockKey, requestId, expireTime)) {
                return true;
            }

            try {
                Thread.sleep(retryInterval);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return false;
            }
        }
        return false;
    }
}

4.3 Redisson分布式锁实现

// Redisson分布式锁实现(推荐)
@Configuration
public class RedissonConfig {

    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer()
                .setAddress("redis://localhost:6379")
                .setDatabase(0)
                .setConnectionPoolSize(10)
                .setConnectionMinimumIdleSize(5);

        return Redisson.create(config);
    }
}

@Service
public class SeckillService {

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public Result seckill(Long productId, Long userId) {
        String lockKey = "seckill:lock:" + productId;
        String requestId = UUID.randomUUID().toString();

        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁,最多等待3秒,锁自动释放时间10秒
            boolean lockAcquired = lock.tryLock(3, 10, TimeUnit.SECONDS);

            if (!lockAcquired) {
                return Result.error("系统繁忙,请稍后重试");
            }

            // 执行业务逻辑
            return doSeckill(productId, userId);

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return Result.error("系统异常");
        } finally {
            // 释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    private Result doSeckill(Long productId, Long userId) {
        // 1. 检查库存
        String stockKey = "seckill:stock:" + productId;
        Long stock = redisTemplate.opsForValue().decrement(stockKey);

        if (stock < 0) {
            // 库存不足,回滚
            redisTemplate.opsForValue().increment(stockKey);
            return Result.error("商品已售罄");
        }

        // 2. 检查用户是否已经购买过
        String userKey = "seckill:user:" + productId;
        Boolean hasBought = redisTemplate.opsForSet().isMember(userKey, userId);
        if (Boolean.TRUE.equals(hasBought)) {
            // 用户已购买,回滚库存
            redisTemplate.opsForValue().increment(stockKey);
            return Result.error("您已经购买过该商品");
        }

        // 3. 记录用户购买
        redisTemplate.opsForSet().add(userKey, userId);
        redisTemplate.expire(userKey, Duration.ofHours(1));

        // 4. 异步处理订单
        SeckillMessage message = new SeckillMessage();
        message.setProductId(productId);
        message.setUserId(userId);
        message.setRequestId(UUID.randomUUID().toString());

        rabbitTemplate.convertAndSend("seckill.exchange", "seckill.order", message);

        return Result.success("秒杀成功,订单处理中...");
    }
}

5. 秒杀系统完整架构实战:从"双11抢购"到"系统稳定"

5.1 系统架构图:像"智能购物中心"

TypeError: undefined is not an object (evaluating 't.v')

5.2 核心代码实现

// 秒杀控制器
@RestController
@RequestMapping("/seckill")
public class SeckillController {

    @Autowired
    private SeckillService seckillService;

    @PostMapping("/{productId}")
    public Result seckill(@PathVariable Long productId,
                          @RequestParam Long userId) {
        try {
            // 参数校验
            if (productId == null || userId == null) {
                return Result.error("参数不能为空");
            }

            // 执行秒杀
            return seckillService.seckill(productId, userId);

        } catch (Exception e) {
            log.error("秒杀异常: productId={}, userId={}", productId, userId, e);
            return Result.error("系统异常,请稍后重试");
        }
    }

    @GetMapping("/stock/{productId}")
    public Result getStock(@PathVariable Long productId) {
        try {
            Long stock = seckillService.getStock(productId);
            return Result.success(stock);
        } catch (Exception e) {
            log.error("查询库存异常: productId={}", productId, e);
            return Result.error("查询失败");
        }
    }
}

// 秒杀服务
@Service
public class SeckillService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ProductRepository productRepository;

    public Result seckill(Long productId, Long userId) {
        // 1. 预检查:商品是否存在且可秒杀
        Product product = productRepository.findById(productId);
        if (product == null || !product.isSeckillEnabled()) {
            return Result.error("商品不存在或未开启秒杀");
        }

        // 2. 预检查:用户是否已经购买过
        String userKey = "seckill:user:" + productId;
        Boolean hasBought = redisTemplate.opsForSet().isMember(userKey, userId);
        if (Boolean.TRUE.equals(hasBought)) {
            return Result.error("您已经购买过该商品");
        }

        // 3. 预检查:库存是否充足
        String stockKey = "seckill:stock:" + productId;
        Long stock = (Long) redisTemplate.opsForValue().get(stockKey);
        if (stock == null || stock <= 0) {
            return Result.error("商品已售罄");
        }

        // 4. 分布式锁控制并发
        String lockKey = "seckill:lock:" + productId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁,最多等待100ms,锁自动释放时间5秒
            boolean lockAcquired = lock.tryLock(100, 5000, TimeUnit.MILLISECONDS);

            if (!lockAcquired) {
                return Result.error("系统繁忙,请稍后重试");
            }

            // 5. 双重检查:再次检查库存
            stock = redisTemplate.opsForValue().decrement(stockKey);
            if (stock < 0) {
                // 库存不足,回滚
                redisTemplate.opsForValue().increment(stockKey);
                return Result.error("商品已售罄");
            }

            // 6. 记录用户购买
            redisTemplate.opsForSet().add(userKey, userId);
            redisTemplate.expire(userKey, Duration.ofHours(1));

            // 7. 异步处理订单
            SeckillMessage message = new SeckillMessage();
            message.setProductId(productId);
            message.setUserId(userId);
            message.setRequestId(UUID.randomUUID().toString());
            message.setTimestamp(System.currentTimeMillis());

            rabbitTemplate.convertAndSend("seckill.exchange", "seckill.order", message);

            return Result.success("秒杀成功,订单处理中...");

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return Result.error("系统异常");
        } finally {
            // 释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    public Long getStock(Long productId) {
        String stockKey = "seckill:stock:" + productId;
        Long stock = (Long) redisTemplate.opsForValue().get(stockKey);
        return stock != null ? stock : 0L;
    }
}

5.3 性能优化配置

# application.yml
spring:
  redis:
    cluster:
      nodes:
        - 192.168.1.100:7000
        - 192.168.1.100:7001
        - 192.168.1.100:7002
        - 192.168.1.101:7000
        - 192.168.1.101:7001
        - 192.168.1.101:7002
      max-redirects: 3
    lettuce:
      pool:
        max-active: 20
        max-idle: 10
        min-idle: 5
        max-wait: 3000ms
    timeout: 5000ms

  rabbitmq:
    host: 192.168.1.100
    port: 5672
    username: admin
    password: admin
    virtual-host: /
    connection-timeout: 15000
    publisher-confirm-type: correlated
    publisher-returns: true
    listener:
      simple:
        acknowledge-mode: manual
        concurrency: 10
        max-concurrency: 20
        prefetch: 1

# 线程池配置
seckill:
  thread-pool:
    core-size: 20
    max-size: 100
    queue-capacity: 1000
    keep-alive: 60s
    thread-name-prefix: seckill-
// 线程池配置
@Configuration
@EnableAsync
public class ThreadPoolConfig {

    @Bean("seckillExecutor")
    public ThreadPoolTaskExecutor seckillExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(100);
        executor.setQueueCapacity(1000);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("seckill-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        executor.initialize();
        return executor;
    }
}

6. 监控与运维

6.1 关键指标监控

// 监控指标收集
@Component
public class SeckillMetrics {

    private final MeterRegistry meterRegistry;
    private final Counter seckillSuccessCounter;
    private final Counter seckillFailCounter;
    private final Timer seckillTimer;
    private final Gauge stockGauge;

    public SeckillMetrics(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        this.seckillSuccessCounter = Counter.builder("seckill.success")
                .description("秒杀成功次数")
                .register(meterRegistry);
        this.seckillFailCounter = Counter.builder("seckill.fail")
                .description("秒杀失败次数")
                .register(meterRegistry);
        this.seckillTimer = Timer.builder("seckill.duration")
                .description("秒杀处理时间")
                .register(meterRegistry);
        this.stockGauge = Gauge.builder("seckill.stock")
                .description("商品库存")
                .register(meterRegistry, this, SeckillMetrics::getCurrentStock);
    }

    public void recordSeckillSuccess() {
        seckillSuccessCounter.increment();
    }

    public void recordSeckillFail() {
        seckillFailCounter.increment();
    }

    public void recordSeckillDuration(Duration duration) {
        seckillTimer.record(duration);
    }

    private double getCurrentStock() {
        // 返回当前库存数量
        return 0.0; // 实际实现中从Redis获取
    }
}

6.2 健康检查

// 健康检查
@Component
public class SeckillHealthIndicator implements HealthIndicator {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public Health health() {
        try {
            // 检查Redis连接
            redisTemplate.opsForValue().get("health:check");

            // 检查RabbitMQ连接
            rabbitTemplate.convertAndSend("health.exchange", "health.check", "ping");

            return Health.up()
                    .withDetail("redis", "连接正常")
                    .withDetail("rabbitmq", "连接正常")
                    .withDetail("timestamp", System.currentTimeMillis())
                    .build();

        } catch (Exception e) {
            return Health.down()
                    .withDetail("error", e.getMessage())
                    .withDetail("timestamp", System.currentTimeMillis())
                    .build();
        }
    }
}

7. 最佳实践总结:从"菜鸟"到"架构师"的成长之路

7.1 高并发系统设计原则:像"盖房子"一样设计系统

  1. 分层架构:Web层、服务层、数据层分离(就像房子的地基、主体、装修)
  2. 缓存优先:多级缓存,减少数据库压力(就像在门口放个快递柜,不用每次都敲门)
  3. 异步处理:消息队列解耦,提高响应速度(就像"先下单,后制作")
  4. 分布式锁:保证数据一致性(就像"一人一票"的入场券)
  5. 监控告警:实时监控系统状态(就像房子的"智能监控系统")

7.2 常见问题与解决方案

问题 原因 解决方案 生活比喻
超卖问题 并发扣减库存 分布式锁 + Redis原子操作 像"限流门",一次只能进一个人
重复下单 用户重复提交 分布式锁 + 幂等性控制 像"防重复按钮",按一次就够了
系统雪崩 服务依赖过多 熔断器 + 降级策略 像"保险丝",一个坏了不影响其他
数据不一致 缓存与数据库不同步 缓存更新策略 + 最终一致性 像"同步更新",确保信息一致

7.3 性能优化建议:像"老司机"一样优化系统

// 性能优化示例(像老司机开车,既快又稳)
@Service
public class OptimizedSeckillService {

    // 1. 使用本地缓存减少Redis访问(像在车里放个水杯,不用每次都去服务站)
    @Autowired
    private Cache<String, Object> localCache;

    // 2. 批量处理减少网络开销(像拼车,一次拉多人)
    public void batchProcessOrders(List<SeckillMessage> messages) {
        // 批量处理逻辑
    }

    // 3. 连接池优化(像停车场,提前规划好车位)
    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        GenericObjectPoolConfig<Object> poolConfig = new GenericObjectPoolConfig<>();
        poolConfig.setMaxTotal(20);        // 最大连接数(最多20个车位)
        poolConfig.setMaxIdle(10);         // 最大空闲连接(平时保持10个车位)
        poolConfig.setMinIdle(5);          // 最小空闲连接(至少5个车位)
        poolConfig.setMaxWaitMillis(3000); // 最大等待时间(最多等3秒)

        return new LettuceConnectionFactory(redisClusterConfiguration(), poolConfig);
    }

    // 4. 异步处理优化(像外卖配送,不用等,先下单后处理)
    @Async("seckillExecutor")
    public CompletableFuture<Void> asyncProcessOrder(SeckillMessage message) {
        // 异步处理逻辑
        return CompletableFuture.completedFuture(null);
    }
}

🎯 总结:从"双11抢购"到"系统架构师"

通过本文的学习,我们就像从"双11抢购的用户"变成了"设计抢购系统的架构师",掌握了高并发架构设计的核心要点:

  1. 系统设计原则:CAP理论、BASE理论指导架构设计(就像盖房子的设计图纸)
  2. 多级缓存架构:本地缓存 + Redis缓存,提升系统性能(就像在门口放快递柜,不用每次都敲门)
  3. 消息队列设计:RabbitMQ实现异步处理和解耦(就像智能邮局,先投递后处理)
  4. 分布式锁实现:Redis和Redisson保证数据一致性(就像银行金库的钥匙管理)
  5. 秒杀系统实战:完整的架构设计和代码实现(就像从设计到施工的完整流程)

高并发系统设计是一个系统工程,需要从架构设计、技术选型、代码实现、监控运维等多个维度综合考虑。就像盖房子一样,不仅要考虑美观,更要考虑实用性和安全性。只有掌握了这些核心技能,才能设计出真正高性能、高可用的系统。

记住:好的架构师不是天生的,而是在解决一个又一个实际问题中成长起来的!


📚 扩展阅读