秒杀 之 超卖问题

通过本节能学到什么?

  1. 什么是抢购的超卖现象?
  2. 常见的解决思路有哪些?最好的解决思路是什么?

目录

1、引出问题

2、怎么解决

3、拓展

4、实际场景


1、引出问题

在做抢购系统的时候,我们首先应该想到的是怎么才能避免超卖,比如说:库存只有100,结果卖了200。这种情况肯定是不能接受的。如果我们不在代码中针对该问题进行相应处理,很有可能就会造成这种不良后果。

比如:

MySQL,Redis常见错误处理方式,下面用伪代码来展示下:

<?php 
    # 查询数据库存放的库存
    $goods_num = $this->goods_db->get_goods_num($goods_id);
    
    # 判断库存
    if($goods_num >=1)
    {
        # 用户和该订单绑定等处理
        
        # 减库存
    }

?>

如上就是我们最常见的处理方式。我们来分析下上面这段代码是怎么造成超卖问题的:

当剩余库存为1 ,同时有两名用户请求数据。此时他们同时走到第6行代码,因为此时他们从第3行代码查询到的库存都是1,所以都进入到了if语句里面。都进行了减库存处理,导致库存变成了-1。

 

 

2、怎么解决

首先我们要明确解决该问题的核心原则:于所有的用户对于库存的读写操作必须是串行的!

举例理解:

并行:多位用户同时检查库存,发现有剩余之后同时减库存。如上面的伪代码就是并行。

串行:用户1检查库存--有剩余之后减库存--用户2检查库存--有剩余之后减库存--用户3检查库存--有剩余之后减库存...... 如果回归到上面的伪代码上,就意味着上面的伪代码要执行的话,必须一个人接一个人的执行,不能多人同时执行。

 

方案:

方案一:Mysql中可以应用悲观锁和乐观锁。

因为该方式不是最好的实现方式,不再展开去讲,可以参考该文章了解下。

方案二(最好):Redis的消息队列。

还是用php代码来处理下

<?php
    #########################后台创建商品侧################################################
    # 在创建商品库存的时候,同时创建一个该商品的redis list key ,来存放该商品所有的库存。  
    $goods_num = 100;
    $goods_id  = 1;
    $goods_list_key = 'goods_num:'.$goods_id;
    for($i=0; $i<$goods_num; $i++)
    {
        $Redis->Lpush($goods_list_key,1);
    }
    # 经过上面一番操作,$goods_list_key已经存放了100个元素,每个元素都是1
    #########################################################################
    
    ......
    
    #########################前台用户抢购商品侧###############################################
    $goods_id  = 1;
    $goods_list_key = 'goods_num:'.$goods_id;
    $user_get_goods = $Redis->Lpop($goods_list_key);
    if(!empty($user_get_goods)))
    {
        # 用户和商品建立绑定关系
        
        # 减库存(到MySQL或者Redis减库存都行,不过一般这种落地数据都会采用放到MySQL中)
    }
    #########################################################################

?>

 

下面来分析下,上面这段代码是如何避免掉超卖问题的:

当商品的库存只剩下1的时候,此时有两位用户同时来取商品。第一个用户把库存取走(pop)之后;第二个用户再来取库存(pop)的时候,发现什么也没取到,那么就直接返回就行,也不需要再去减库存。

 

3、拓展

注意实际项目中一般稍微复杂一点,还有加一条逻辑:一位用户只能取一个商品,多次来的请求并不能多次取商品。这条也非常常见的要求,毕竟万一有用户来刷,没有限制的话,所有商品可能都被该用户取走。

思路:只需要在进行领取之前查询下用户是否已经领取过即可

 

4、实际场景

最近做了一个需求,虽然不是抢购,但是也是有库存限制。由于没有针对超卖问题进行处理,就出现了库存为-1的情况。如上面优化之后就没有问题了。

 

 

参考文档:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
秒杀系统中,超卖和少卖是常见的问题超卖指的是在秒杀活动中售卖的商品数量超过了实际库存数量,而少卖则是指实际库存数量大于秒杀活动中售卖的商品数量。这两个问题都会给商家和消费者带来一些困扰。 超卖问题可能出现在秒杀活动赶上热销商品时,由于系统处理延迟、并发请求等原因,导致实际销售数量超过了库存数量。这会造成一些消费者购买了实际上已经售罄的商品,给消费者带来不满和投诉,同时也对商家的声誉和销售利益造成损害。 少卖问题则是指实际库存数量大于秒杀活动中售卖的商品数量。这可能是由于系统数据同步延迟、售卖过程中出现异常等原因导致的。对于商家来说,这会导致潜在的销售机会的浪费,同时也会让消费者失去购买心愿。 为了解决超卖和少卖问题秒杀系统需要做到以下几点: 1. 系统实时库存更新:系统需确保在秒杀活动中及时更新库存数量,避免超卖和少卖的情况发生。 2. 并发请求处理:系统需要具备足够的并发处理能力,能够同时处理大量用户的请求,避免因系统处理延迟而导致的超卖问题。 3. 限制购买数量:通过设置购买数量限制,可以避免某些用户一次性购买大量商品,从而平衡库存和需求之间的关系。 4. 实时监控和报警机制:建立实时监控和报警机制,及时发现库存异常变动,以便及时采取措施解决问题。 总之,秒杀系统超卖和少卖问题是需要特别留意的,商家需要通过合理的系统设计和管理措施来减少这类问题的发生,以提供良好的用户体验和保护商家的利益。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值