概述
首先先确认方案
方案1:下单后减库存;用户下单,然后库存加锁,判断库存是否充足,用户下单完成,减库存,最后释放库存锁。
方案2:支付才减库存;用户支付,然后库存加锁,判断库存是否充足,用户支付完成,减库存,最后释放库存锁。
当然还有其他方案,这里只阐述我的思考。
(库存加锁的过程有个小细节请看附1)
两种方案的比较
方案1
1)假如100个人同时下单,只有一个人能下单成功。
2)此时订单应该有一个过期状态,如果订单过期,库存加锁并回写库存后释放锁。
方案2
1)100个人可以同时下单,但是100个人同时付款时,只有一个人付款成功。
正常情况下,商品加入购物车的用户>>>下单的用户>=付款的用户。如果从库存加锁的角度来说,在下单的时候加锁,那么高并发下用户体验可能比较差,因为同时下单只有一个人能下单成功,而且服务器性能可能会比较差;下单的请求变多,那么请求加锁的次数也变多了,而支付的用户可能小于下单的用户,请求加锁的次数理论上会少不少。
我的建议是:
普通的电商项目我认为方案一就足够了,因为下单的流程简单,而支付可能涉及到很多业务,如果支付里面锁库存,考虑的东西会有点多。
但是在高并发下或者秒杀场景下,那可能就要在支付的时候锁库存。从业务角度来说,肯定是手快有,手快无;从代码的角度来说,支付跟减库存高度耦合,出现超卖、库存不一致情况大大降低,如果是下单锁库存,万一用户取消订单,那是不是库存要加回去,这种情况下高并发出现库存与实际消费不一致的可能性比较大。
实现方式以及优化
商品订单库存这个业务不仅仅只有用户下单这个功能,还要在管理后台提供商家修改库存的入口。那么这样就有两处需要用到库存,必须要考虑竞争问题。
单体架构的实现
单体架构实现这个业务是最简单的,但是性能也是最差的。
单体架构中,不管是用户操作还是管理员后台操作库存都放在里面,然后部署到机器上。此时库存锁是个全局锁,用户下单,管理员要修改库存都要从全局的库存锁拿到锁,执行完业务代码再释放。
这种单体架构就会出现一个问题,耦合度太高,一旦管理后台修改库存占用库存锁,那么用户就不能下单购买商品了。如果是购买量不多的业务,单体架构是可以满足基本需求的,这种实现成本低,易维护但不能支撑高并发。
像大部分中小型公司,一天的订单我感觉也就1000以内,单体架构完全够用了,并不需要改造成下面的方案,增加幂级的复杂度
优化方案
如果说业务增长块订单量增大,那么上面的单体架构就有局限性了。特别是现在互联网公司的架构大部分都是微服务分布式。
1)首先,每次加锁后,都需要从数据库查询库存,判断库存,然后用户下完单也要操作数据库修改库存。数据库的操作是需要时间成本的,大流量下如果其中一个用户下单时间太慢,其他用户都要等待他处理完,用户体验太差
2)其次现在架构大部分是分布式、微服务的,用户下单减库存和管理后台修改库存一般都是拆分为两个服务--下单服务和库存服务
优化的第一步。要解决下单因为操作数据库耗时过长的问题,我们可以把库存放到缓存中(一般是redis),然后对redis中的库存加redis锁,执行下单,对redis中的库存进行减库存。这么做的好处是提升了用户下单的速率,加大了并发量;其次用户下单跟管理后台的业务解耦了,为以后拆分服务做扩展。如下图:
虽然提升了性能,但是新问题出现了,数据一致性问题。现在业务是独立分开了,用户下单,redis加锁,操作redis的库存就可以了,同样管理后台修改库存,加锁操作数据库的库存就可以了。但是怎么保证这两个地方的库存一致性呢?
使用消息队列让数据库的库存进行减库存
用户下单成功后向消息队列发送一条消息,然后在管理后台业务中消费消息,进行减库存,如图:
如果保证了消息的可靠性传输,那么即可保证用户下单后的库存与数据库的库存达到最终一致性。
停售同步库存
如果管理后台要修改库存并且同步到redis上去要怎么办?可行的方案是让商家停止出售商品,然后判断redis的库存跟数据库的库存是否一致,若一致,那么商家即可修改库存,修改后更新数据库库存和redis库存。如果不一致,那么你就要知道是否管理后台还没消费完消息队列,还是其他问题,没消费完让商家等一段时间就行了,是其他问题的话程序员就妥妥的背锅吧,必须从日志系统里面查查具体是哪里出问题。
微服务分布式
其实就是把单体架构拆分,具体解决思路不变。具体要看业务把,如果订单不多的话,没必要拆分为订单服务和库存服务或者把他们解耦出来,一开始的单体架构就够用了。至于优化的方案,我感觉独角兽或者大型公司才会用到。也可能我技术角度或者业务角度没达到那种高度。
其他问题
因为之前面试,经常就问到商品库存这个问题,现在只是写个自己的思考,肯定有错误的地方。还有很多问题就不去考虑了,毕竟我没做过这个业务,例如生产上因为用户点击过快、网络问题导致的订单重复提交。
题外话
算是给点建议吧,一开始找工作尽量找稳定的公司,然后干几年积累技术。我面试的时候因为简历是3年换了3家公司,每次面试都要问我为啥经常离职。而且大公司简历几乎就进不了面试,中小型公司技术面过了,但是HR面因为这个问题也可能会把你刷了。还有就是要从业务上考虑,业务才能驱动技术的提升。(PS:广州真的是一线城市么?工资是真的低,干IT别来广州,别来广州,别来)
附1:
高并发或者秒杀场景下,不管是方案1还是方案2,如果库存为0时,是否还是每次都锁库存去走一遍流程,即库存加锁,判断库存是否充足,用户下单完成,减库存,最后释放库存锁,答案肯定是否的。
想一想java实现单例模式的代码,用了两个判断语句,那么这个场景我们也可以使用这种方式。外面先去查询一次库存,再判断是否为0,如果为0直接返回,如果不为0 ,那么库存加锁,判断库存是否充足,用户下单(或支付)完成,减库存,最后释放库存锁。以下单锁库存为例:
最后
以上就是典雅路人为你收集整理的商品订单库存一致性问题的思考的全部内容,希望文章能够帮你解决商品订单库存一致性问题的思考所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复