高并发核心技术 - 订单与库存

  • 问题:
    一件商品只有100个库存,现在有1000或者更多的用户来购买,每个用户计划同时购买1个到几个不等商品。如何保证库存在高并发的场景下是安全的。
    1.不多发
    2.不少发
  • 下单涉及的一些步骤
    1.下单
    2.下单同时预占库存
    3.支付
    4.支付成功真正减扣库存
    5.取消订单
    6.回退预占库存
  • 什么时候进行预占库存
    方案一:加入购物车的时候去预占库存。
    方案二:下单的时候去预占库存。
    方案三:支付的时候去预占库存。
    分析:
    方案一:加入购物车并不代表用户一定会购买,如果这个时候开始预占库存,会导致想购买的无法加入购物车。而不想购买的人一直占用库存。显然这种做法是不可取的。
    方案二:商品加入购物车后,选择下单,这个时候去预占库存。用户选择去支付说明了,用户购买欲望是比 方案一 要强烈的。订单也有一个时效,例如半个小时。超过半个小时后,系统自动取消订单,回退预占库存。
    方案三:下单成功去支付的时候去预占库存。只有100个用户能支付成功,900个用户支付失败。用户体验不好,就像你走了一条光明大道,一路通畅,突然被告知此处不通行。而且支付流程也是一个比较复杂的流程,如果和减库存放在一起,将会变的更复杂。

所以综上所述:
选择方案二比较合理。

  • 重复下单问题

    1. 用户点击过快,重复提交两次。
    2. 网络延时,用户刷新或者点击下单重复提交。
    3. 网络框架重复请求,某些网络框架,在延时比较高的情况下会自动重复请求。
    4. 用户恶意行为。

解决办法

    1. 在UI拦截,点击后按钮置灰,不能继续点击,防止用户,连续点击造成的重复下单。
    2. 在下单前获取一个下单的唯一token,下单的时候需要这个token。后台系统校验这个 token是否有效,才继续进行下单操作。
  • 如何安全的减扣库存

同一个用户或者多个用户同时抢购一个商品的时候,我们如何做到并发安全减扣库存?

方法1 :

不考虑库存安全的写法:(1)减可用 (2)加预占 (3)库存数据不安全

分析:
                       在高并的场景下,假设库存只有 2 件 ,两个请求同时进来,抢购改商品,购买数量都是 2.
                       A请求 此时去获取库存,发现库存刚好足够,执行扣库存下单操作。
                       在 A 请求为完成的时候(事务未提交),B请求 此时也去获取库存,发现库存还有2. 此时也去执行扣库存,下单操作。库存剩 2 ,但是卖出了 4 。最终数据库库存数量将变为 -2 ,所以库存是不安全的。

方法2 :

这个操作可以保证库存数据是安全的。

分析:

在方法1 的基础上 ,更新库存的语句,增加了可用库存数量 大于 0, availableNum - num >= 0 ;实质是使用了数据库的乐观锁来控制库存安全,在并发量不是很大的情况下可以这么做。但是如果是秒杀,抢购,瞬时流量很高的话,压力会都到数据库,可能拖垮数据库。

方法3:

该方法也可以保证库存数量安全。

分析:

利用Redis 分布式锁, 强制控制 同一个商品,同时只能一个请求处理下单。 其他请求返回 ‘系统繁忙稍后再试!’;
                      强制把处理请求串行化,缺点并发不高 ,处理比较慢,不适合抢购等方案 。
                      用户体验也不好,明明看到库存是充足的,就是强不到。
                      相比方案2减轻了数据库的压力。

方法4 :

可以保证库存安全,满足高并发处理,但是相对复杂一点。

分析:
                      利用Redis increment 的原子操作,保证库存安全。 事先需要把库存的数量等其他信息保存到Redis,并保证更新库存的时候,更新Redis。
                      进来的时候 先 get 库存数量是否充足,再执行 increment。以 increment > 0 为准。
                      检查库存 与 减少库存 不是原子性的。
                      检查库存的时候技术库存充足也不可下单;否则造成库存不安全,原来类似 方法1.
                      increment 是个原子操作,已这个为准。

redisService.increment(key, -req.getNum().longValue()) >= 0 说明库存充足,可以下单。

redisService.increment(key, -req.getNum().longValue()) < 0 的时候 不能下单,次数库存不足。并且需要 回加刚刚减去的库存数量,否则会导致刚才减扣的数量 一直买不出去。数据库与缓存的库存不一致。

次方法可以满足 高并抢购等一些方案,真正减扣库存和下单可以异步执行。

  • 订单时效问题,订单取消等
    为保证商家利益,同时把商品卖给有需要的人,订单下单成功后,往往会有个有效时间。超过这个时间,订单取消,库存回滚。

为每笔订单设置 有效时间 可用参考这个:
         http://jblog.top/article/details/254951

订单取消后,可利用MQ 回退库存等。

源自

原文地址:https://www.cnblogs.com/mzhaox/p/11181337.html

时间: 2024-10-10 16:49:41

高并发核心技术 - 订单与库存的相关文章

Java生鲜电商平台-高并发核心技术订单与库存实战

Java生鲜电商平台-高并发核心技术订单与库存实战 一. 问题 一件商品只有100个库存,现在有1000或者更多的用户来购买,每个用户计划同时购买1个到几个不等商品. 如何保证库存在高并发的场景下是安全的? (1)不多发 (2)不少发 二. 下单的步骤 (1)下单 (2)下单同时预占库存 (3)支付 (4)支付成功真正减扣库存 (5)取消订单 (6)回退预占库存 三. 什么时候进行预占库存? (1)方案一:加入购物车的时候去预占库存 (2)方案二:下单的时候去预占库存 (3)方案三:支付的时候去

高并发核心技术 - 幂等性与分布式锁

高并发核心技术之 - 幂等性 1. 什么是幂等性 幂等性就是指:一个幂等操作任其执行多次所产生的影响均与一次执行的影响相同.用数学的概念表达是这样的: f(f(x)) = f(x).就像 nx1 = n 一样, x1 就是一个幂等操作.无论是乘以多少次结果都一样. 2. 常见的幂等性问题 幂等性问题经常会是由网络问题引起的,还有重复操作引起的. 场景一:比如点赞功能,一个用户只能对同一片文章点赞一次,重复点赞提示已经点过赞了. 示例代码: public void like(Article art

Redis适用于高并发的递增、递减功能

递增指令:incr(默认从0开始) 递减指令:decr(默认从0开始,递减会出现负数,这点跟memcache不一样,mc到0) 如下: 附上shardedJedisPool和JedisCluster的两种实现方式: shardedJedisPool: @Override public Long decr(String key) { ShardedJedis jedis = null; Long result = 0l; try { jedis = shardedJedisPool.getReso

高并发的核心技术-幂等的实现方案(转)

高并发的核心技术-幂等的实现方案 一.背景 我们实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返回一样的结果. 例如: 1. 前端重复提交选中的数据,应该后台只产生对应这个数据的一个反应结果. 2. 我们发起一笔付款请求,应该只扣用户账户一次钱,当遇到网络重发或系统bug重发,也应该只扣一次钱: 3. 发送消息,也应该只发一次,同样的短信发给用户,用户会哭的: 4. 创建业务订单,一次业务请求只能创建一个,创建多个就会出大问题. 等等很多重要的情况,这些逻辑都需要幂等的特性来支持.

mysql处理高并发,防止库存超卖

先来就库存超卖的问题作描述:一般电子商务网站都会遇到如团购.秒杀.特价之类的活动,而这样的活动有一个共同的特点就是访问量激增.上千甚至上万人抢购一个商品.然而,作为活动商品,库存肯定是很有限的,如何控制库存不让出现超买,以防止造成不必要的损失是众多电子商务网站程序员头疼的问题,这同时也是最基本的问题. 从技术方面剖析,很多人肯定会想到事务,但是事务是控制库存超卖的必要条件,但不是充分必要条件. 举例: 总库存:4个商品 请求人:a.1个商品 b.2个商品 c.3个商品 程序如下: beginTr

PHP解决抢购、抽奖等阻塞式高并发库存防控超量的思路方法

如今在电商行业里,秒杀抢购活动已经是商家常用促销手段.但是库存数量有限,而同时下单人数超过了库存量,就会导致商品超卖甚至库存变负数的问题. 又比如:抢购火车票.论坛抢楼.抽奖乃至爆红微博评论等也会引发阻塞式高并发问题.如果不做任何措施可能在高瞬间造成服务器瘫痪,如何解决这个问题呢? 这里提出个人认为比较可行的几个思路方法: 方案一:使用消息队列来实现 可以基于例如MemcacheQ等这样的消息队列,具体的实现方案这么表述吧 比如有100张票可供用户抢,那么就可以把这100张票放到缓存中,读写时不

PHP解决抢购、秒杀、抢楼、抽奖等阻塞式高并发库存防控超量的思路方法

如今在电商行业里,秒杀抢购活动已经是商家常用促销手段.但是库存数量有限,而同时下单人数超过了库存量,就会导致商品超卖甚至库存变负数的问题.又比如:抢购火车票.论坛抢楼.抽奖乃至爆红微博评论等也会引发阻塞式高并发问题.如果不做任何措施可能在高瞬间造成服务器瘫痪,如何解决这个问题呢?这里提出个人认为比较可行的几个思路方法: 方案一:使用消息队列来实现 可以基于例如MemcacheQ等这样的消息队列,具体的实现方案这么表述吧比如有100张票可供用户抢,那么就可以把这100张票放到缓存中,读写时不要加锁

转 mysql处理高并发,防止库存超卖

原文地址: mysql处理高并发,防止库存超卖 今天王总又给我们上了一课,其实MySQL处理高并发,防止库存超卖的问题,在去年的时候,王总已经提过:但是很可惜,即使当时大家都听懂了,但是在现实开发中,还是没这方面的意识.今天就我的一些理解,整理一下这个问题,并希望以后这样的课程能多点. 先来就库存超卖的问题作描述:一般电子商务网站都会遇到如团购.秒杀.特价之类的活动,而这样的活动有一个共同的特点就是访问量激增.上千甚至上万人抢购一个商品.然而,作为活动商品,库存肯定是很有限的,如何控制库存不让出

EF+MySQL乐观锁控制电商并发下单扣减库存,在高并发下的问题

下订单减库存的方式 现在,连农村的大姐都会用手机上淘宝购物了,相信电商对大家已经非常熟悉了,如果熟悉电商开发的同学,就知道在买家下单购买商品的时候,是需要扣减库存的,当然有2种扣减库存的方式, 一种是预扣库存,相当于锁定库存, 一种是直接扣减库存. 我们采用的是预扣库存的方式,预扣库存的时候,在SalesInfo表中,将最大可售数量MaxSalesNum减去购买数量,用一条SQL语句来表示这个业务,就是下面这个样子的: update salesinfo set MaxSalesNum=MaxSa