首页 > 其他分享 >秒杀场景-转发

秒杀场景-转发

时间:2024-08-15 11:29:53浏览次数:10  
标签:场景 版本号 goods 数据库 用户 amount 库存 秒杀 转发

抢购业务数据库需要考虑的点如下:

 

一、超卖现象

 

场景如下:

 

   库存数是5。现在3个用户来购买,a用户购买2个,b用户购买3个,c用户购买1个。合起来就是准备购买6个。

 

   如果三个用户是同时并发购买,会出现怎样的情况呢?

 

  每个用户进行减库存的时候,语句类似于:

 

1 update goods set amount=amount-购买数量 where goods_id=xxx。

  

 

mysql会锁定这一行数据(使用innodb存储引擎),数据库加的是排他锁。根据排他锁的特点:其他线程不能读、不能写此行数据。

 

排他锁情况下,那么其他用户就是等待状态了。

 

   1、A用户执行update的时候,锁定库存数据。update执行完毕后,减去了2个后,mysql自动释放锁。

 

   2、b用户执行,减去了3个。此时,已经卖掉5个库存了。库存数为0了。

 

    3、但是c用户接着执行,Update goods set amount=amount-1 where goods_id=xxx

 

          结果库存数量变成-1了。

 

思考:把库存数量字段的类型,设计成正数类型,不允许出现负数,会怎么样呢?

 

测验结果:数据库会直接报错。通不过。

 

 

解决办法:只有库存数量,大于或等于购买数量的时候,才能去减库存。其他情况,提示信息,库存不足。

 

sql语句如下:

 

update goods set amount=amount-购买数量 where goods_id=xxx AND amount>=购买数量

 

 

这样,轮到c执行的时候,由于使用了amount>=购买数量做限制条件,update语句返回的受影响的行数是0,意味着执行失败了。直接提示,库存不足。

 

 

 

二、并发抢购造成的速度慢问题

 

 

1、实现方式对比:悲观锁与乐观锁

 

第一种问题中描述的超卖现象,其实是并发抢购时出现的情况。用到的是数据库内带的加排他锁方式,阻止了其他线程读取、访问数据,这要等待操作完毕后其他线程才能操作,这种方式是悲观锁方式。这样会等待下去。

 

 

使用数据库的悲观锁,是避免了数据并发更新,但是,加锁毕竟是很耗服务器资源的,用户要等待下去。所以并不能达到好的性能和高并发。

 

业界使用乐观锁的办法来解决:使用数据库的乐观锁是通用解决办法。通用锁实现了版本控制。不会进行排斥掉。减少资源的消耗。

 

乐观锁是相对悲观锁而言的,使用的是更加宽松的锁定方式。

 

乐观锁,通俗说就是:修改数据的时候,不给数据加锁。

 

既然不加锁,其他线程也是可以访问、修改数据。但是,修改的时候会获取一个版本号,只有版本号符合了,才算更新成功。

 

不成功的,都算抢购失败。

 

 

 

2、乐观锁的具体实现方式

 

 

  乐观锁的机制与代码版本库svn很相似,这种方式,叫做多版本记录方式。

 

  如果在我提交代码之前用本地代码的版本号与服务器做对比,如果本地版本号小于服务器上最新版本号,则提交失败,产生冲突代码,让用户决定选择哪个版本继续使用。



  逻辑描述:

 

if(之前读取到行的版本号+1=数据库此行现在的版本号+1){

 

      //符合预期,数据库的数据没有给其他用户修改掉。可以直接写入数据了

 

}else{

 

      //数据已经被修改了。所以当前的版本已经落后了。不能进行更新

}

 

例子:

 

给表goods加一个版本字段version,用来记录行数据值的版本号。

 

版本号version字段,设计成一个正整数,比如是时间戳。每次修改后,要将version字段的值加1:  1496916794、1496916795、1496916796、1496916797、1496916798.................

 

读数据的时候,顺便将版本号的值读取出来。update时,做版本号对比,如下:

 

1、先读取这个商品的信息,顺便将版本号读取出来

1 select  amount,version from t_goods where goods_id=8899;

  

2、更新数据

 

1 2 3 update  goods set amount=amount-2,version=version+1 where goods_id=8899  and version=#{version}  and amount>=2;

  

 

sql解释:

 

#{version}是之前select读取到的版本号,填入进去,意思是只能修改这样的。

 

修改的时候,限制条件-必须版本号等于原来的版本号才能去修改。否则不能修改。更新成功的同时,版本号要加1。

 

优点:使用数据库的乐观锁是通用解决办法。通用锁实现了版本控制。线程之间同时操作,不加锁,线程不用等待了。减少了数据库资源的消耗。

 

缺点:会增加cpu的计算开销。不过值得这样做,由于没有加锁进行阻塞,用户不用等待结果,很快能等到执行结果了,用户体验更好。抢购的并发数其实提高了。

 

 

 

三、减库存和下单保持在一个事务内

 

如果不在一个事务内,可能出现两种现象:

 

1、订单入库失败、减库存成功。发现订单入库失败,减库存就不要继续进行下去了。

 

2、订单入库成功、减库存失败。实际下了20个订单,库存却没有减。数据不一致了。

 

 

四、虚拟库存和真实库存两套方案

 

考虑几种情况:

 

1、有些人下单完后,最终并不会去付款。如果一下单就马上减库存,很多人下单,最终并不会去付款,可能导致库存数最后为0,别的用户无法下单了。而实际中仓库中却有库存在,这样库存数据是不准确的。

2、什么时候减库存? 是下单完成减库存、还是付款完后减库存呢?

 

 付款后,才减库存,可能出现的现象:用户下完单,接着去付款,结果库存不够了。这样用户体验很不好。

 

 下完单就减库存,能够保证用户下单只要付款,就一定能买到这个商品。用户体验较好。

 

 针对一些人下单后,不付款,占着库存资源,其他人无法下单。这个问题好解决,给付款设置一个有效期限,比如30分钟。超过这个时间,库存就释放掉了。

 

 具体技术实现办法:下单后,马上减去库存。另外设置一个定时脚本,扫描超过30分未支付的订单,把订单中的商品数量返回到库存中去。

 

 

  为什么使用虚拟库存和真实库存两套方案?

 

  假设库存数是50,a订单购买了5个件商品,支付完毕,库存数减去5,库存数变成了45件。由于还没有发货,实际库存中还有50件商品。这样会出现混淆了。

 

  使用两套库存记录方案是有必要的!

 

  •   下单-操作虚拟库存数
  •    商品发货出库-操作真实库存数

 

     真实库存数,记录下仓库中这件商品真有多少件。真实库存,其实非常方便内部人员查看,它只有商品出库,这个库存才减。

     虚拟库存,用来应对商品购买的。表明,还有多少数量可以给用户去购买。并不表示仓库中的库存数。

 

 

五、频繁读库存的压力

  因为,每次点击,都要读取库存,判断:有没有库存。如果读库存走的是数据库判断,很多人来抢购的情况下,数据库的压力会很大。

 

  假设是1万个用户同时访问抢购页面。数据库接受的访问次数是1万个并发。

  用户还要进行刷新页面操作,由于每次刷新都会走数据库判断库存。数量会更大。数据库的压力就更大了。

  所以最好是,把库存总数,缓存在redis中去。

  内存中缓存的库存数量,只用来做读判断。这样压力扛住了。而更改数据库的库存总数了,程序马上要把库存总数,同步到缓存中去。

 

系统抗压力问题

 

一、如何限流

二、如何防止恶意刷数据。

 

      防止的就是写代码去频繁请求,为了识别是机器还是人工。加友好一点的验证码。

 

转载自:https://www.cnblogs.com/wangtao_20/p/7057861.html

标签:场景,版本号,goods,数据库,用户,amount,库存,秒杀,转发
From: https://www.cnblogs.com/zhuoneng/p/18360547

相关文章

  • Java数组篇[10]:数组的常见应用场景
    哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者......
  • Transformer模型在自然语言处理中有哪些具体的应用场景?
    关注我,持续分享逻辑思维&管理思维&面试题;可提供大厂面试辅导、及定制化求职/在职/管理/架构辅导;推荐专栏《10天学会使用asp.net编程AI大模型》,目前已完成所有内容。一顿烧烤不到的费用,让人能紧跟时代的浪潮。从普通网站,到公众号、小程序,再到AI大模型网站。干货满满。学成后可......
  • 蒙特卡洛1000个风光场景并通过削减法|聚类法得到几个典型场景(matlab&python实现)
        目录1 对风光的认识2 风电DG出力概率模型 2.1 风速分布特性2.2 风电DG有功出力3 光伏DG出力概率模型 3.1 光照强度分布特性3.2光伏DG有功出力 4Python代码实现4.1数据4.2Python代码 4.3结果  5Matlab实现5.1数据5.2Matlab代码 5.......
  • 【Azure 存储服务】Azure文件能实现的功能及业务场景的系列问题
    问题一:Azure文件提供的部署方式,云部署/本地部署?当前可用的是哪种方式Azure文件存储可以用于替换或补充传统的本地文件服务器或连接到网络的存储(NSA)设备。Azure文件是云服务,存储的文件都在AzureCloud里,开通本地防火墙445端口(运行在portal上自动生成的powershell脚本),就可以......
  • 边缘计算技术解决行业痛点,TSINGSEE智能分析网关V4技术特点与应用场景解析
    一、行业背景随着人工智能(AI)技术的飞速发展,边缘计算硬件作为其核心组成部分,正逐步成为市场的新宠。这些硬件不仅提升了数据处理和分析的效率,还极大地降低了数据传输的延迟,为各行各业的智能化转型提供了有力支持。1、痛点1)传统企业智能化不足,海量的数据缺乏实时性的服务,网络负......
  • Transformer和LSTM相结合--应用场景
    将Transformer和LSTM相结合可以在多种自然语言处理(NLP)任务中取得显著效果,特别是在需要捕捉长短期依赖的场景中。结合的目的是利用Transformer的全局注意力机制和LSTM的短期记忆能力,实现更强大的序列建模。以下是这种结合应用的场景、工作原理以及实现代码。1.应用场景文本生......
  • 在K8S中,你用的flannel是哪个工作模式及fannel的底层原理如何实现数据报文转发的?
    在Kubernetes(K8S)中,Flannel是一个广泛使用的容器网络接口(CNI)插件,它提供了一种简单而有效的方法来为集群中的每个容器分配网络,并确保它们可以互相通信。Flannel支持多种工作模式来实现数据报文的转发,其中最常见的是VXLAN、UDP和HOST-GW三种模式。1.Flannel的工作模式VXLAN模式:......
  • UEFI Shell 的基本操作和应用场景,适合初学者了解和入门 UEFI Shell 的使用。 UEFI She
    UEFIShell是一种提供命令行接口的环境,用于与UEFI固件进行交互。UEFI(统一可扩展固件接口)是计算机启动过程中的一种固件接口,替代了传统的BIOS。UEFIShell提供了一种方式,让用户在启动操作系统之前进行系统管理和配置。主要特点命令行界面:UEFIShell提供一个类似于操作......
  • Openwrt 配置 PS5 端口转发
    前言前阵子申请了公网IP通过了想远程串流玩PS5通过Socat配置端口转发后仅桌面端Chiaki可以远程串流PS5改用Openwrt的防火墙转发使PSPlay+Chiaki都可串流环境Openwrt22.03.6状态>概览>固件版本步骤打开网络>防火墙>端口转发点击添加配置4个端口9295TC......
  • 并发场景下,缓存失效处理场景
    并发场景下,缓存失效,需要从数据库或下游查询缓存中的数据。若并发流量都请求到下游,导致下游压力较大,可通过如下方式进行处理:importjava.util.concurrent.*;publicclassSingleFlight{privatefinalConcurrentMap<Object,CompletableFuture<?>>cache=newConcurrent......