06 | 秒杀系统“减库存”设计的核心逻辑
06 | 秒杀系统“减库存”设计的核心逻辑
讲述:秭明
时长11:40大小5.34M
减库存有哪几种方式
减库存可能存在的问题
大型秒杀中如何减库存?
秒杀减库存的极致优化
总结一下
赞 22
提建议
精选留言(106)
- Null2019-06-28兄台,我看过你的书,感觉你的这个主题和你的书一样,都写的相当的泛,尤其是减库存这个地方,更泛,看了之后依然没办法对一些稍微细节的实现处理作出判断,能麻烦写的稍微细点吗?共 44 条评论225
- 周龙亭2018-10-07下单和扣库存两个操作的事务性是怎么做的?
作者回复: 可以分两步来做,先创建订单但是先不生效,然后减库存,如果减库存成功后再生效订单,否则订单不生效
共 9 条评论31 - 刘小刘2018-12-21老师,我觉得你讲的不太明白,你并没有说实际情况下同步是怎样解决并发的,没看到您给的方案,只看到您在评论回复里否定了队列异步处理的方式
作者回复: 解决的办法就是尽可能避免产生锁,比如根据商品ID进行分库分表设计;再有就是减少锁的粒度例如阿里对MySQL做了定制优化,可以提升MySQL的并发度
共 2 条评论19 - Geek_c19c962018-10-16我们的库存都放在redis里面,读和减库存都在redis里面操作,redis会定时将库存放到mysql中做备份,
作者回复: 😉
共 9 条评论11 - 公号-技术夜未眠2018-10-06许老师好,我有一个想法,只是没有在实践中这样做过,请指教: 能否借用"数据库水平拆分"的思想? 具体思路如下: 库存在数据库的表中就只有一行数据,上面的方案都是对这一条记录进行频繁更新,是非常"热"的热点数据。我们能否将该行数据拆分到不同的数据库中,这些数据库的库存记录之和就是原始库存数量。这样能否会降低数据库的写压力,提高吞吐量?展开
作者回复: 实际上,商品都是进行分库分表的,例如根据商品id进行水平拆分 分库分表就是提高吞吐量
共 4 条评论11 - Coder42018-10-06这种无只能在串行隔离级别才能用吧,不然肯定超售。。。UPDATE item SET inventory = CASE WHEN inventory >= xxx THEN inventory-xxx ELSE inventory END
作者回复: 数据库层不都是串行操作吗😊
共 15 条评论10 - 永光2018-10-06老师,你好, 你提到秒杀商品减库存直接放到缓存系统中实现,也就是直接在缓存中减库存或者在一个带有持久化功能的缓存系统(如 Redis)中完成。这种实现并发读写怎样保持数据一致?以及是不是要用分布式缓存?
作者回复: 前面有个同学的类似的问题回答过,可以看一下
10 - shawn2018-10-14个人做法, 针对确定库存,提前下好单,下单人留空,订单短时间内失效 订单id压入Redis队列, 请求来到,订单队列lpop,队空则返回失败, pop出来的订单补充下单人为当前用户, 如果订单过期失效则再次下同一商品的空单存入队列 这个设计可以考虑单个Redis不够用的时候将队列分组,利用轮转或时间戳hash将请求分配到不同队列, 想问下老师,这个和扣数字库存相比,会不会有更好的并发性能呢?展开
作者回复: 说实话,没看出来哪里性能会更好😄 不过提前下单的思路还比较新颖,你的思路我理解,但是这样就把一个事情分两次来做,会增加了复杂度,有可能导致得不偿失
共 6 条评论9 - 一笑奈何2018-10-06老师,问下单机mysql 1s内能抗大约多大的QPS? 大约。
作者回复: 我印象中单实例一般能抗7-8k左右
共 2 条评论9 - 宇宙浪子2020-03-04减库存是秒杀系统的难点,尤其是涉及到跨集群时如何既要满足性能又要做到数据一致性,整篇文章只是泛泛而谈,具体细节和核心难点都没讲解决方法。希望能讲的细致些,泛泛而谈没啥意义8
- 宁宁2018-12-06下单减库存的方式存在问题是有些用户下单缺不付款,有一个补偿方案就是付款设置超时时间,一旦超时取消订单,同时发送消息到消息对列,库存服务订阅消息,把库存加回去!8
- 我是李香兰小朋友2018-10-13“按照商品维度设置队列顺序执行”这句话是什么意思?可以举例说明一下吗?谢谢老师
作者回复: “按照商品维度设置队列顺序执行”的意思就是,为了防止同一个商品对数据库的操作占用太多的数据库资源,所以采用队列的方式,让其他商品也有公平的机会得到数据的响应,例如如果秒杀的时候,秒杀商品肯定占用大量的请求,数据库的连接池有可能都被秒杀商品占用了,如果不做队列的话,那么其他商品就得不到数据库执行机会了。加入我们分10个队列,那么秒杀商品就会落在这10个队列中的一个,那么最多也就占用机器10分之一的资源。
8 - 大麦2018-10-12秒杀是短时间大量请求,使用下单即锁库存方式,可以通过一个 redis 队列记录下单,一个redis key 记录数量 num,超出的库存下单失败,这样大量请求在 redis 层即可被处理。 通过 num 与库存的判断来解决无效订单。 下单端通过队列异步消费下单。 对于前端,用户下单成功,即进入redis 队列的,响应给前端可以轮询。 没有的,直接提示抢购失败。展开
作者回复: 异步下单的方式,也是一个思路,例如在一些场景下其实已经在使用,例如一些支付场景中,付了款以后,前端页面中会有一个转圈,等个几秒钟再告诉你结果。 这种方式我个人觉得对用户不太友好,就是要让用户等个几秒钟,而不是像同步的方式能及时得到反馈结果
共 3 条评论7 - moliniao2018-10-08老师,使用应用排队方式,入队后返回,然后app端轮询请求下单结果吗?
作者回复: 秒杀web请求一般不用排队,谁先到谁先执行。 排队一般更多是在服务端的内部请求时发生,而且是在异步请求时通过消息队列来处理
7 - 诗泽2018-10-18看到有同学说下单排队可以用请求队列来做,想问一下请求队列里存放的是请求数据吧,即用户请求数据入队列之后请求立即返回,后台异步处理请求数据,那处理的结果如何告知用户?是前端发起轮训请求吗?如果是轮训的话又会占用服务器不少连接资源吧? 如果请求队列里直接存的是http 请求的话服务器端也是会持有大量未释放的http 长连接。 所以请教一下实际当中一般请求队列这部分是怎么做的呢?
作者回复: 大家对请求队列这块问的比较多,后面相关的问题我统一回答一下吧
6 - 约书亚2018-10-15好多同学提到基于redis减库存,我看阿里云的文档时,里面也提到了阿里双11秒杀就用的这种方式,不知道是不是真的?
作者回复: 早期用过😉
共 3 条评论6 - 坏坏的举哥2019-09-05库存分为三种,可售库存、未付款库存、未发货库存,三者想加是总库存; 下单时,可售库存减,未付款库存加;付款后,未付款库存减,未发货库存加; 库存操作使用数据库乐观锁机制; 针对秒杀场景,可以针对sku进行合并扣减库存,先放在多队列进行合并数目,然后再一次写到库中; 这才是实际可行方案。展开5
- null2018-11-01方法一和方法三是不是没啥区别? 方法一:下单减库存,但是用户不支付,订单超时释放库存 方法三:预扣库存,用户下单时扣库存,超时释放库存 区别是不是在“超时”时长?但这个也是人为决定的,所以方法一和方法三是同一种方案?展开
作者回复: 如果方法一有后续的超时回补库存,那么就差不多了
5 - 对方正在输入.......2018-10-06预扣库存和扣库存有什么区别?怎么预扣库存?
作者回复: 预扣是有预定的意思,如果未付款还会补回来 而扣库存就实际的减去库存了 每次预扣都可以创建一条记录,如果这条记录超时了就删掉,剩下的库存就是总库存减去预扣的库存
5 - Runlion2018-12-21我又一个想法:就是讲总库存分成几批分别储存在不同的服务器上,比如100个商品分别放在5台服务器abcd,每台放20个商品,用户通过抢购进入网关,我们可以制定一个路由策略比如用户id等于1-100的去a抢购,id等于201-300去b抢购,以此类推,整个抢购活动结束后在整体同步到数据库,这样做减少了数据的并发计算,由于是抢购也不存在单台服务商品库存过剩的情况,您觉得这个思路怎么样?
作者回复: haha,有意思,不过我们的商品库存本来就是分库分表的,不同的商品库存本身就不在一台机器上的。
4