博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
电商场景:并发扣库存,怎么保证不超卖又不影响并发性能
阅读量:4290 次
发布时间:2019-05-27

本文共 1497 字,大约阅读时间需要 4 分钟。

潘戈来了 2019-09-22 13:03:27

任何电商平台的一个主业务场景就是:

  1. 加入购物车;
  2. 去结算,填写/选择收货地址;
  3. 检查/扣减库存,生成订单并付款;

其中第三步,检查/扣减库存,常规代码实现如下:

判断剩余库存量,如果库存足够,则做扣减操作;

select stock from goods_stock where sku = 'a1'if(stock - buy_num) >= 0){ //如果库存大于等于购买数量 stock = stock - buy_num; update goods_stock set stock = stock where sku = 'a1'}

一般来讲,一张订单不会只买一种商品,如果有多个,则需要重复上述

这种方式最大的问题就是不支持并发,哪怕并发数是2个,都有可能出现库存扣减错误;

因为获取剩余库存与实际update 有个时间差,假设此时有两个下单请求,都购买a1,此时剩余库存为1,这两个下单请求同时 select 请求到了 剩余的1个库存,都能顺利的执行后续的操作,最终会卖出2个,造成超卖;

解决这个问题,最简单的方式就是加入事务,但是,事务会造成锁表、锁行,效率低下;

一种解决方式:在update的时候,加入一个条件:

update goods_stock set stock = stock where sku = 'a1' and stock = old_stock

更直接的一种方式如下,不用先查询剩余库存,直接update

update goods_stock set stock = stock - buy_num where sku = 'a1' and (stock-buy_num) >= 0 ;

因为update 会把并发串行执行,高并发下,库存不足时,会执行失败;

现在设想这么一个场景,1万用户,抢购N种商品,每种商品库存100件。每个用户可能都会同时抢购n种商品;

按实际经验估算,3万用户以下,利用mysql的update机制,足够应付,此处不考虑更大并发的情况,更大并发场景需要引入redis等解决方案了,后面专门发文阐述;

考虑事务效率不佳,此处我们抛弃掉事务,引入队列来实现库存扣减失败的回滚;

boolean isSuccess = true;for (sku in goods){ if(update goods_stock set stock = stock - sku[num] where sku = sku[sn] and (stock-sku[num]) >= 0 ){ sku_success[] = {sku[sn],sku[num]} }else{ //扣减失败 push_queue(sku_success[]) //队列存入需要回滚的商品编码及对应数量,异步处理; isSuccess = false; }}if (isSuccess){ //生成订单 createOrder(); }else{ //抛出错误提示:某商品库存不足,无法生成订单;}

说明:文中 用户数 != 并发数,一般抢购用户多集中于第一分钟,在高并发下,一般认为没有出现响应超过500ms的接口,说明系统工作正常,用户体验合格,用户基本在30秒内能够完成浏览商品,加入购物车,下单的操作。

以上场景在不引入redis的情况下,仅利用mysql的锁机制,承受3万用户一分钟的高访问,产生6万-10万单是可行的。

如果并发场景要求更高,能采用的方式可以是 mysql 多主多从,引入redis/zk 等。

转载地址:http://hwggi.baihongyu.com/

你可能感兴趣的文章
javascript原型详解(1)
查看>>
netty源码分析之-处理器详解(9)
查看>>
javascript原型对象存在的问题(3)
查看>>
javascript原型继承(1)
查看>>
javascript原型继承-实现extjs底层继承(2)
查看>>
javascript设计模式-建立接口的方式(1)
查看>>
javascript设计模式-单体singleton模式(2)
查看>>
javascript设计模式-链式编程(3)
查看>>
大型高并发与高可用缓存架构总结
查看>>
javascript设计模式-工厂模式(4)
查看>>
javascript设计模式-组合模式(6)
查看>>
javascript设计模式-门面模式(7)
查看>>
javascript设计模式-享元模式(10)
查看>>
javascript设计模式-代理模式(11)
查看>>
Executor相关源码分析
查看>>
react之setState解析
查看>>
elasticsearch7.3版本已经不需要额外安装中文分词插件了
查看>>
【重大好消息】elasticsearch 7.3版本已经可以免费使用x-pack就可以设置账号和密码了,让你的数据不再裸奔
查看>>
解决使用logstash中jdbc导入mysql中的数据到elasticsearch中tinyint类型被转成布尔型的问题的方法
查看>>
elasticsearch7.3版本环境搭建(一)elasticsearch安装和配置
查看>>