概述
一、 秒杀抢购场景下防止商品超卖的技术实现思路
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
最后
以上就是含蓄豆芽为你收集整理的秒杀抢购场景下防止商品超卖的技术实现思路一、 秒杀抢购场景下防止商品超卖的技术实现思路的全部内容,希望文章能够帮你解决秒杀抢购场景下防止商品超卖的技术实现思路一、 秒杀抢购场景下防止商品超卖的技术实现思路所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复