Spring Boot + Redis 多方案实现高并发秒杀业务需求

大环境影响,目前各地消费券发放火热,促消费、扩内需,已成2025主旋律,那么,如何保证消费券有序发放呢,在系统设计和实操中,会遇到哪些问题?应该注意什么?

思考

我们可能会遇到的问题?

  1. 超卖问题
  2. 高并发问题
  3. 安全性问题
  4. 数据库性能瓶颈问题

如何解决

  • 我们先来看传统意义的库存扣减实现,先查询库存,如果还有库存,那么则库存-1,没有库存,则提示下单失败,很简单。
  • 但会存在一个问题,并发情况下,如果 A 和 B 都同时查到库存 = 1,都去进行了扣减,那么最后就会产生超卖的情况。
  • 那我们将该查询和扣减操作加上锁,就解决了二者的问题,如果是多实例,就升级为分布式锁。
  • 那么,第一个方案就出来了,效率如何,我们来看一下。

测试场景

基于优惠券秒杀场景,初始化优惠券至 Redis 缓存中,设置库存为 500 张。

	@GetMapping("/init/{couponId}")
    public String init(@PathVariable String couponId) {
   
    
    
        RedisUtil.set(couponId, 500);
        return RedisUtil.get(couponId);
    }

这里,我们通过创建测试接口,使用压测工具 Jmeter,设置线程组如下:
线程数:10
Ramp-Up 时间:1秒
循环次数:100
模拟1秒 10 个并发,1000 个请求,那么抢到优惠券的概率为 50%。

秒杀方案一

分布式锁。

  • 由于现阶段基本都是分布式架构了(单机也适用),之前封装好的分布式锁工具,直接拿来用:点我
    @GetMapping("/seckill/{couponId}")
    public String seckill(@PathVariable String couponId) {
   
    
    
        return RedissonUtil.lock(couponId, () -> {
   
    
    
            int couponNum = Integer.parseInt(RedisUtil.get(couponId));
            log.info("优惠券库存:{}", couponNum);
            Assert.isTrue(couponNum > 0, "优惠券抢完了...");

            // 库存 - 1
            RedisUtil.set(couponId, couponNum - 1);
            return