摘要:

本篇博文是“Java秒杀系统实战系列文章”的第十二篇,本篇博文我们将借助压力测试工具Jmeter重现秒杀场景(高并发场景)下出现的各种典型的问题,其中最为经典的当属“商品库存超卖”的问题,在本文我们重现这种问题,并对问题进行分析!

内容:

一个正规的、声称能承受高并发请求的系统的背后应该经历了一些不为人知的经历,这个秒杀系统也是如此,一般而言,这些经历都是比较残酷的,在本文中我们将重现出这样的经历!即采用压力测试工具Jmeter压测这个秒杀系统的“秒杀接口”!

在进入秒杀压测环节前,我们将之前的“接收前端用户的秒杀请求对应的控制器方法”复制一份,用于给JMeter压测使用,即在KillController中复制出一个新的“执行秒杀请求”的方法,其代码如下所示:

//商品秒杀核心业务逻辑-用于压力测试
@RequestMapping(value = prefix+"/execute/lock",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public BaseResponse executeLock(@RequestBody @Validated KillDto dto, BindingResult result){if (result.hasErrors() || dto.getKillId()<=0){return new BaseResponse(StatusCode.InvalidParams);}BaseResponse response=new BaseResponse(StatusCode.Success);try {//不加分布式锁的前提Boolean res=killService.killItem(dto.getKillId(),dto.getUserId());if (!res){return new BaseResponse(StatusCode.Fail.getCode(),"不加分布式锁-哈哈~商品已抢购完毕或者不在抢购时间段哦!");}}catch (Exception e){response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());}return response;
}

之后,我们便可以开心的进入玩耍环节。

(1)双击JMeter的启动脚本jmeter.sh,进入JMeter的主界面,新建一个测试计划,然后在该测试计划下新建一个线程组(设定1秒并发1000个线程,后续还可以调整线程数),紧接着是新建HTTP请求项以及CSV数据文件的读取配置等等,如下图所示:

其中,userId参数用于模拟参与秒杀~抢购的用户,其取值将来源于上图中的“CSV数据文件设置”选项的文件,在这里Debug设定了10个用户,如下图所示:

值得一提的,“HTTP消息头管理器”选项是必需的,用于指定提交的数据的数据格式,即Content-Type的取值为application/json(因为我们的后端接口设置的就是 consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)。

在开始之前,我们设定了killId=3的商品作为秒杀~抢购的对象,并在数据表中设定其“可抢购数量/库存”的值total为6,如下图所示:

(2)万事俱备只欠东风,下面我们点击JMeter主界面的启动,即可发起“1秒内并发1000个线程”的请求,而这1000个线程对应的用户的Id,即userId将随机从上述的CSV文件中读取。在出现结果之前,我们先从理论的角度上进行分析:10个用户抢购库存只有6个的书籍,那么理论上结果应该是“库存变为0,被抢购完毕,然后在item_kill_success表中会有6条,而且也应该仅有6条秒杀成功的订单记录”!

然而,理论归理论,现实还是很残酷的!

(3)点击JMeter的启动按钮,此时可以观察控制台的输出信息以及数据库表item_kill和item_kill_success,会发现一连串“惨不忍睹”的数据记录,如下图所示:

对于初次接触“高并发秒杀业务场景”的童鞋可能会感觉到惊讶,“明明经过Postman测试过了呀,为啥还会出现这种情况!”,有点百思不得其解!

然鹅呢,Debug想说的是“事出必有因”,而出现这种情况,单单抱怨是屁用都木有的,还得去源头进行分析,即从代码的层次进行分析!

(4)我们再次来回顾一下所写的“秒杀接口”的核心逻辑,如下图所示:

(1)当用户在前端界面疯狂的点击“抢购”按钮时,我们上面接口将会接收到“汹涌潮水般”的用户秒杀请求,首次秒杀,很多用户都是第一次秒杀该商品,故而A流程大部分用户都将通过考核;

(2)同时,由于B流程的逻辑是判断是否可抢,而很明显,大家都是第一次来抢的,这个商品也没那么快被抢完,故而B流程大家也将通过考核;

(3)到了C流程,就需要扣减库存了,由于库存的扣减在这里只是单纯的“减一”的操作,故而在C这个流程,很多人将可以成功减一;

(4)最后大家势如破竹,赶紧到了D流程,D流程是用于“生成秒杀成功的订单”,记录用户秒杀过的商品的痕迹,同时也是为了服务于A流程;这个时候的D已经不做什么判断了(大家可以看到核心的判断其实在于A流程,这也就是问题出现的致命根源),大家就直接插入一条成功的记录了。

因此,最终就出现了“库存超卖”、“同一个用户可以抢到多次”等各种莫名其妙的问题;

通过上面的分析,其实Debug已经指出来了,问题产生的根源在于高并发的情况下D流程的处理并没有为A流程的处理赢得足够的时间,即“生成一条秒杀成功后的订单记录” 并没有及时的为 “判断用户是否已经秒杀过了~是否已经有对应的订单记录了” 的流程很好的服务!

那么在下面的篇章中,我们将从各个角度进行优化,包括数据库级别Sql的优化、代码逻辑的优化、分布式锁的引入等等(当然这些是从开发的层面来讲的,其实还有运维的层面也可以优化,比如Nginx的负载均衡、中间件的集群部署提高高可用等等)!

补充:

1、目前,这一秒杀系统的整体构建与代码实战已经全部完成了,完整的源代码数据库地址可以来这里下载:https://gitee.com/steadyjack/SpringBoot-SecondKill 记得Fork跟Star啊!!!

2、由于相应的博客的更新可能并不会很快,故而如果有想要快速入门以及实战整套系统的,可以考虑联系Debug获取这一“Java秒杀系统”的完整视频教程(课程是收费的!),当然,大家也可以点击下面这个链接 https://gitee.com/steadyjack/SpringBoot-SecondKill 联系Debug或者加入相应的技术交流群进行交流!

3、实战期间有任何问题都可以留言或者与Debug联系、交流;技术交流群:605610429(Java实战基地交流1群)

4、最后,不要忘记了关注一下Debug的技术微信公众号:

Java秒杀系统实战系列~JMeter压力测试重现秒杀场景中超卖等问题相关推荐

  1. Java秒杀系统实战系列~数据库级别Sql的优化与代码的调整

    摘要: 本篇博文是"Java秒杀系统实战系列文章"的第十三篇,从本篇文章开始我们将进入"秒杀代码优化"环节,本文将首先从数据库级别Sql的优化入手,结合调整秒杀 ...

  2. java 模块 分工_Java秒杀系统实战系列~构建SpringBoot多模块项目

    摘要:本篇博文是"Java秒杀系统实战系列文章"的第二篇,主要分享介绍如何采用IDEA,基于SpringBoot+SpringMVC+Mybatis+分布式中间件构建一个多模块的项 ...

  3. Java秒杀系统实战系列~RabbitMQ死信队列处理超时未支付的订单(转)

    转自: https://juejin.cn/post/6844903903130042376 文末有源代码,非常棒 摘要: 本篇博文是"Java秒杀系统实战系列文章"的第十篇,本篇 ...

  4. Java秒杀系统实战系列~分布式唯一ID生成订单编号

    摘要: 本篇博文是"Java秒杀系统实战系列文章"的第七篇,在本博文中我们将重点介绍 "在高并发,如秒杀的业务场景下如何生成全局唯一.趋势递增的订单编号",我们 ...

  5. Java秒杀系统实战系列~构建SpringBoot多模块项目

    摘要:本篇博文是"Java秒杀系统实战系列文章"的第二篇,主要分享介绍如何采用IDEA,基于SpringBoot+SpringMVC+Mybatis+分布式中间件构建一个多模块的项 ...

  6. java 唯一编号_Java秒杀系统实战系列~分布式唯一ID生成订单编号

    摘要: 本篇博文是"Java秒杀系统实战系列文章"的第七篇,在本博文中我们将重点介绍 "在高并发,如秒杀的业务场景下如何生成全局唯一.趋势递增的订单编号",我们 ...

  7. java设计前期工作基础和存在的困难_Java秒杀系统实战系列-基于Redisson的分布式锁优化秒杀逻辑...

    本文是"Java秒杀系统实战系列文章"的第十五篇,本文我们将借助综合中间件Redisson优化"秒杀系统中秒杀的核心业务逻辑",解决Redis的原子操作在优化秒 ...

  8. Java秒杀系统实战系列~基于Redisson的分布式锁优化秒杀逻辑

    摘要: 本篇博文是"Java秒杀系统实战系列文章"的第十五篇,本文我们将借助综合中间件Redisson优化"秒杀系统中秒杀的核心业务逻辑",解决Redis的原子 ...

  9. java 秒杀代码_Java秒杀系统实战系列~商品秒杀代码实战

    摘要: 本篇博文是"Java秒杀系统实战系列文章"的第六篇,本篇博文我们将进入整个秒杀系统核心功能模块的代码开发,即"商品秒杀"功能模块的代码实战. 内容: & ...

最新文章

  1. 青龙羊毛——去闲转(教程)
  2. 【Mac】【环境变量】
  3. 小宝机器人的储存容量_新iPad Pro储存越来越大:甚至到1T!您应该购买哪种存储容量呢?...
  4. Windows保护模式学习笔记(五)—— 任务段任务门
  5. Codeforces - 961E Tufurama
  6. git 撤销全部的commit_Git 撤销 Commit
  7. Storm 1.1.0 集群安装
  8. 独立线性度 最佳直线
  9. 机器人 魂斗罗铁血兵团_《魂斗罗铁血兵团:反叛》XBLA游戏下载
  10. 昆仑通态如何连接sqlserver数据库_sqlserver数据库怎么开启远程连接,给到别人访问...
  11. 设计模式-策略模式(Strategy)
  12. ESP8266 MQTT
  13. vijos一元三次方程求解
  14. 区块链在供应链领域的应用案例
  15. pyodbc 测试连接 SQL Server 数据库
  16. Cypress初探(一)
  17. 云原生架构下的 API 网关实践: Kong (三)
  18. c语言过磅系统,衡安无人值守地磅称重系统过磅流程
  19. Matplotlib不显示中文解决办法
  20. 修改注册表来解决Microsoft Office中word和excel表格打开新文件时前面最小化的文件重新弹出显示的问题

热门文章

  1. 详解数字美元白皮书:可能和你想的不一样
  2. linux如何设置Java环境变量呢?
  3. Shopify和其他电子商务平台上的微数据
  4. 使用Maple进行c语言程序修复,Gro¨ bner基方法验证乘法器的Maple实现
  5. 【蓝桥杯】三羊献瑞-算法题JAVA解
  6. 携手并进,合作共赢 ▏麒麟信安授权北京辰极智程为京、津、冀省级区域总代理签约仪式举行
  7. HTML基础(P24-P44)
  8. 小学数学加减法测试软件,小学数学加减乘除出题软件
  9. 中国抓到了勒索病毒作者!!
  10. 《奇葩说》詹青云:熬过那些日子,你才有资格过不被人左右的人生