电商中的库存管理实现-mysql与redis
2017-01-04 22:45
435 查看
库存是电商系统的核心环节,如何做到不少卖,不超卖是库存关心的核心业务问题。业务量大时带来的问题是如何更快速的处理库存计算。
此处以最简模式来讨论库存设计。
以下内容只做分析,不能直接套用,欢迎各位同道前来交流指正
库存模型:sku,num。
sku是标示商品的唯一编号,num是商品的数量。
订单处理时需扣减商品库存。
mysql隔离级别READ-COMMITTED
扣减1001库存7:
10-7=3;
3>0;
开始扣减库存
UPDATE
在串行执行情况下以上逻辑是正确的处理方式。
如果是并发执行,可能会出现这种情况:
10-7=3;
库存在另外一个线程中被修改为5
UPDATE
库存最终被修改为3
一共卖出5+7=12个商品,实际总商品数是10,超卖发生。
为解决超卖引入如下方案:
10-7=3;
3>0;
开始扣减库存
库存在另外一个线程中被修改为5
UPDATE
update失败,超卖解决。
考虑到订单的商品有多个,那在并发执行的情况下是否还是正常呢?
现有订单1,订单2同时处理,都是1001扣减库存5,1002扣减库存10
订单1:
UPDATE
UPDATE
订单2:
UPDATE
UPDATE
若sql执行情况是订单1先修改1001,订单2修改1002,这个时候产生死锁,有一个订单必然会失败。
少卖发生。
如果是订单2中第二个商品是1003会怎么样呢?
两个订单的库存修改会变成串行执行。
这种情况下会带来性能下降的问题,事务超时的时候会发生多个订单失败的情况。
多个订单失败后如果订单依然要处理,此时库存没有扣减,又会发生超卖。
结论:mysql可以保证数据一致性和持久性,但是性能不高,在量级较高的情况下库存并没有控制好少卖超卖的情况。
redis的读写速度快,数据操作都在内存中运行,性能必然比mysql高。
string类型提供了decrby方法,可以以原子方式对string做减法。
对1001库存减5:
decrby 1001 5
获得返回值,如果小于0则执行
incrby 1001 5
并且所有相关数据回滚
在多线程环境中会有多个订单同时回滚,库存充足的情况。产生这种现象后,失败的订单可以留待下次再行处理。
但是库存的值并不能用来做实时计算,因为失败订单的库存没有进行计算。
redis没有事务,无法保证数据一致性。
结论:redis解决了性能问题,但是数据一致性无法保证。
最后,不管用mysql还是redis 都各有优缺点.
此处以最简模式来讨论库存设计。
以下内容只做分析,不能直接套用,欢迎各位同道前来交流指正
库存模型:sku,num。
sku是标示商品的唯一编号,num是商品的数量。
订单处理时需扣减商品库存。
mysql实现
库存初始数据:mysql隔离级别READ-COMMITTED
扣减1001库存7:
10-7=3;
3>0;
开始扣减库存
UPDATE
stockSET num=3 WHERE sku=1001;
在串行执行情况下以上逻辑是正确的处理方式。
如果是并发执行,可能会出现这种情况:
10-7=3;
库存在另外一个线程中被修改为5
UPDATE
stockSET num=3 WHERE sku=1001;
库存最终被修改为3
一共卖出5+7=12个商品,实际总商品数是10,超卖发生。
为解决超卖引入如下方案:
10-7=3;
3>0;
开始扣减库存
库存在另外一个线程中被修改为5
UPDATE
stockSET num=num-7 WHERE num>=7 AND sku=1001;
update失败,超卖解决。
考虑到订单的商品有多个,那在并发执行的情况下是否还是正常呢?
现有订单1,订单2同时处理,都是1001扣减库存5,1002扣减库存10
订单1:
UPDATE
stockSET num=num-5 WHERE num>=5 AND sku=1001;
UPDATE
stockSET num=num-10 WHERE num>=10 AND sku=1002;
订单2:
UPDATE
stockSET num=num-10 WHERE num>=10 AND sku=1002;
UPDATE
stockSET num=num-5 WHERE num>=5 AND sku=1001;
若sql执行情况是订单1先修改1001,订单2修改1002,这个时候产生死锁,有一个订单必然会失败。
少卖发生。
如果是订单2中第二个商品是1003会怎么样呢?
两个订单的库存修改会变成串行执行。
这种情况下会带来性能下降的问题,事务超时的时候会发生多个订单失败的情况。
多个订单失败后如果订单依然要处理,此时库存没有扣减,又会发生超卖。
结论:mysql可以保证数据一致性和持久性,但是性能不高,在量级较高的情况下库存并没有控制好少卖超卖的情况。
redis实现
mysql的缺点是如此显而易见,为了解决这个问题,现在引入redis。redis的读写速度快,数据操作都在内存中运行,性能必然比mysql高。
string类型提供了decrby方法,可以以原子方式对string做减法。
对1001库存减5:
decrby 1001 5
获得返回值,如果小于0则执行
incrby 1001 5
并且所有相关数据回滚
在多线程环境中会有多个订单同时回滚,库存充足的情况。产生这种现象后,失败的订单可以留待下次再行处理。
但是库存的值并不能用来做实时计算,因为失败订单的库存没有进行计算。
redis没有事务,无法保证数据一致性。
结论:redis解决了性能问题,但是数据一致性无法保证。
其它
为解决mysql问题,可以结合异步定时扣减库存,队列做。最后,不管用mysql还是redis 都各有优缺点.
相关文章推荐
- java swing mysql实现的仓库库存管理系统源码附带视频指导教程
- 电商营销方式抢购,秒杀Redis原子出队列lpop方法作为剩余库存判断条件的实现方式(2)
- 基于redis集群实现的分布式锁,可用于秒杀商品的库存数量管理,有测试代码(何志雄)
- 电商营销方式抢购,秒杀Redis原子出队列lpop方法作为剩余库存判断条件的实现方式(2)
- 基于redis集群实现的分布式锁,可用于秒杀商品的库存数量管理,有测试代码(何志雄)
- 基于redis集群实现的分布式锁,可用于秒杀商品的库存数量管理,有測试代码(何志雄)
- Redis实践:使用Pub/Sub实现对服务器群的管理监控
- 通过Gearman实现MySQL到Redis的数据同步
- windows下实现mysql备份至异地,并结合计划任务实现自动管理。
- 通过Gearman实现MySQL到Redis的数据同步
- 用SQL实现学籍管理系统相关的表操作(转载来的部分已修改)用mysql5.5做的
- vsftpd+mysql+apache实现给虚拟用户分配不同目录及权限并实现远程管理
- 通过Gearman实现MySQL到Redis的数据同步
- 通过Redis的Pub/Sub实现对服务器群的监控管理
- TM框架-MySQL版本(实现动态开发和权限管理)-附下载地址
- Java实现MySQL在线管理
- 如何用MySQL 命令来实现账户管理