热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

商品订单库存一致性问题的思考

首先先确认方案方案1:下单后减库存;用户下单,然后库存加锁,判断库存是否充足,用户下单完成,减库存,最后释放库存锁。方案2:支付才减库存;用户支付,然后库存加锁,判断库存是否充足,

首先先确认方案

方案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 ,那么库存加锁,判断库存是否充足,用户下单(或支付)完成,减库存,最后释放库存锁。以下单锁库存为例:

 

 



推荐阅读
  • 云原生应用最佳开发实践之十二原则(12factor)
    目录简介一、基准代码二、依赖三、配置四、后端配置五、构建、发布、运行六、进程七、端口绑定八、并发九、易处理十、开发与线上环境等价十一、日志十二、进程管理当 ... [详细]
  • 一次上线事故,30岁+的程序员踩坑经验之谈
    本文主要介绍了一位30岁+的程序员在一次上线事故中踩坑的经验之谈。文章提到了在双十一活动期间,作为一个在线医疗项目,他们进行了优惠折扣活动的升级改造。然而,在上线前的最后一天,由于大量数据请求,导致部分接口出现问题。作者通过部署两台opentsdb来解决问题,但读数据的opentsdb仍然经常假死。作者只能查询最近24小时的数据。这次事故给他带来了很多教训和经验。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 2021最新总结网易/腾讯/CVTE/字节面经分享(附答案解析)
    本文分享作者在2021年面试网易、腾讯、CVTE和字节等大型互联网企业的经历和问题,包括稳定性设计、数据库优化、分布式锁的设计等内容。同时提供了大厂最新面试真题笔记,并附带答案解析。 ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • Sleuth+zipkin链路追踪SpringCloud微服务的解决方案
    在庞大的微服务群中,随着业务扩展,微服务个数增多,系统调用链路复杂化。Sleuth+zipkin是解决SpringCloud微服务定位和追踪的方案。通过TraceId将不同服务调用的日志串联起来,实现请求链路跟踪。通过Feign调用和Request传递TraceId,将整个调用链路的服务日志归组合并,提供定位和追踪的功能。 ... [详细]
  • “您可以从三个选项中(快速、便宜或好)选择两个”提出这个问题的人可能不是可观测性工程师。但也可能是,在可观测性方面,决定您 ... [详细]
  • 熟练掌握Spring Cloud,终于成为Java工程师的面试门槛 ... [详细]
  • 基于分布式锁的防止重复请求解决方案
    一、前言关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求。而这样的重复请求如果是幂等的(每次请求的结果都相同,如查 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • ElasticSerach初探第一篇认识ES+环境搭建+简单MySQL数据同步+SpringBoot整合ES
    一、认识ElasticSearch是一个基于Lucene的开源搜索引擎,通过简单的RESTfulAPI来隐藏Lucene的复杂性。全文搜索,分析系统&# ... [详细]
author-avatar
reisen_辉
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有