秒杀抢购场景下防止商品超卖的技术实现思路

一、 秒杀抢购场景下防止商品超卖的技术实现思路

1. 通常解法

方案一:

在购买下单前先查询数据库库存是否大于0进行判断,有库存在进行减库存下单操作,反之下单失败。

具体做法:用户点击活动页面时,后台进行查询数据库当中的number(库存)字段。判断number库存是否大于0,如若小于0,则给用户返回库存不足抢购失败。如若大于0,则进行下单操作,生成订单号,然后进行修改库存(number-1),判断执行操作是否成功,如若成功给用户返回抢购成功,如若失败则给用户返回抢购失败。

问 题: 当并发量大的时,数据库number字段会出现负数,所以会出现超卖问题。

方案二:

1)将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,如果继续减库存是将会返回false

​ 2) 开启事务锁住操作的行

具体做法:

用户操作->开启事务->查询数据

->判断number是否大于0

->如若失败返回库存不足,进行事务回滚

->如若成功,进行下单操作

->修改库存number-1,进行判断

->如若更改库存失败,返回抢购失败

->如若执行成功,进行事务提交,返回抢购成功

问 题: 事务开启时,会产生一个独占锁,当并发量高的时候,就会造成有些SQL请求阻塞,从而导致并发用户出现请求超时或页面无法响应的情况,没有返回数据,只是一个空白页,所以造成用户体验不好,同时也会造成DB服务器压力非常大。

2. 通用大牛级解法

思路:通过消息队列来处理,起到高并发场景下的异步,消峰作用。

具体做法:在活动开始之前,将我们活动的商品放到我们的队列当中,开始后我们需要一个排队队列和抢购结果队列。高并发情况,先将用户插入排队队列,用一个线程循环处理从排队队列顺序取出每一个用户,判断用户是否已在抢购结果队列,如果在,则已抢购,否则未抢购,开始减库存,生成订单,支付结算等操作,同时将订单结果数据同步到MySQL。

3. 解法对比及优缺点:

常见解法,

方案一:在高并发情况下会出现库存为负数也就是超卖的问题,此方案不可取。方案二:确实解决了商品超卖的问题,但是在高并发情况下还是会给DB造成死锁和严重阻塞的情况,且用户体验比较差。

通用大牛解法:这里消息队列可以采用的消息中间件,像RabbitMQ,Kafka,ZeroMQ等等,我们样例演示采用的是redis的list数据类型实现队列,因为redis的pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用,而采用 mysql事务在高并发下性能下降很厉害,文件锁的方式虽然是非阻塞形式,但是用户体验很差。

通过对比,通过消息队列的方式可以对抢购秒送这种高并发场景下进行消峰,有效提高了系统的高可用和高性能, 大大减低数据库的读写压力,同时也提升了用户体验。

4. 延伸及扩展问题回答参考

问题:通过消息队列还有那些常见的应用场景?

解答:

1.在线竞拍,抢购等瞬间多用户高并发的场景都可以通过消息队列来消峰处理

2.在用户生成订单时也会有很多关联操作需要处理,比如:计算用户积分,计算分销商的佣金,给用户发送提醒通知,等等业务逻辑,这些是不需要在下订单那一刻马上完成执行的,所以这种情况下就可以通过消息队列的的形式,将这些非必需的业务进行解耦,异步处理,从而降低订单业务逻辑的拆分解耦,降低单个业务的复杂度。

5. 项目中体现经验的点

项目开发过程中,充分理解消息队列的应用场景,消峰,异步处理和业务解耦。在高并发的场景下可以考虑通过消息队列的进行消峰异步处理,从而适当有效降低服务器的压力,同时也可以对复杂的业务进行拆分解耦,实现了高并发情况下高性能和高可用。

6. 参考资料

RabbitMQ官方文档: https://www.rabbitmq.com/documentation.html

Redis官方文档 : https://redis.io/documentation

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值