高性能问题
Web性能测试 解决方案: JMeter 【不是代码单元,而是场景】
依靠JMH可以完成基本的性能测试,进行代码优化,比如在JVM预热情况下,使用Lambda、Stream比增强for 效率高;
在BS架构流行的当下,需要对场景进行性能测试,比如登录场景,商品购买,支付场景等: 常见的问题:
上面的问题针对的都是web应用,也就是会进行浏览器的访问,都可以依靠性能测试工具—JMeter; 桌面GUI可以允许用户无代码编写脚本,通过后台启动JMeter的方式允许脚本,测试的是场景,而不是JMH的代码单元; (单元 — 集成);
JMeter项目整体测试,JMH代码局部测试优化
直接到官网下载压缩包即可: Apache JMeter - Download Apache JMeter ,Cfeng的JDK为10以上版本,选用的JMeter为5.4.3, 5.3版本出现了一些奇怪的问题
下载之后解压安装, 进入bin目录,点击jmeter.sh就可以允许cmd窗口打开GUI程序,cmd窗口不能关闭
这里可以直接在查看高级系统变量位置将环境变量配置上 ---- 也就是安装目录的bin配置到path中即可,这样可以直接在cmd窗口输入jmeter就可以启动
JMeter可以对多种协议进行测试: 比如常用的http、https、ws、wss、tcp、udp、ftp等以及对NoSQL、MySQL、JMS等数据源进行性能测试
可以直接编写性能测试脚本,也可以通过脚本录制的方式进行性能测试 ---- 网页代理进行页面上的操作,操作流程被录制生成性能测试脚本
Jmeter完成压力测试需要借助各种配置原件,完成一个最简单的抢红包测试,需要借助Http请求的Sampler、查看结果树的Listener、CSV配置辅助的 config Element
基础单元, 各种协议的请求都是由取样器发起的。 比如HTTP请求、FTP请求、JMS发布订阅、Java请求、JDBC请求、TCB请求等、SMTP请求

当然最常用的还是HTTP Request,在其中配置相关的host、port、contextPath、encoding等信息 以及配置相关的请求参数, 请求参数可以使用CSV文件进行指定变量; ${XXX}即可引入文件的数据
主要对上面取样器的各种请求进行辅助配置

配合取样器的HTTP信息头管理器 Http Header Manager、缓存管理器 Http cache manager、 Cookie管理器、JDBC connection Configuration 连接配置、 LDAP Extended Request Defaults LDAP扩展请求,…
主要控制JMeter脚本的执行顺序, 比如从接口请求得到结果,经过逻辑Controller判断之后,执行接口2等, 灵活度更高,包括if控制器、 事务、循环、While、ForEach、仅一次、吞吐量、Switch等
执行取样器前,执行前置处理器,最简单的就是执行Http访问请求前需要 执行的前置处理, 比如HTML链接处理器、HTML URL重写修饰符和取样器超时等
执行取样器后,执行后置处理器,后置处理器包括CSS/JQuery提取器、JSON提取器、边界提取器、BeanShell断言和正则表达式提取器等, 在提取数据后,可以对上个请求的结果参数化,传输到下一个请求中
断言可以验证服务器返回的数据和预期是否相符,如果不相符,可以记录或者停止测试计划,【可以类比SpringBoot自动化测试的断言】,包括响应断言、JSON、大小、HTML、XML、BeanShell
测试计划执行过程中,定时器减缓线程的运行,eg: 线程在请求接口1执行之后,需要暂停若干ms后请求2,包括固定、随机的定时器
监听器主要收集测试结果报告, 主要包括: 查看结果树、断言结果、聚合报告、若有插件: 还可以监听被测试端的CPU和内存
Jmeter的参数化实现方式包括函数、外部文件、提取的上一个接口的数据
JMeter提取数据后,在HTTP请求脚本中通过${变量名称} 使用配置的参数,除请求body外,任何地方都可以使用变量、路径、服务器名称或者IP、端口、协议编码
JMeter函数可以通过函数生成相关的数据供发起HTTP请求

通过这个GUI界面 --》 打开Tools工具 —> 选择Function Helper Dialog 函数助手对话框
在这里面可以选择BeanShell、或者Random随机数字、RandomString随机字符串、Random随机时间、splt字符串拆分、property自定义数值、UUID和char等
如果上面选择RandomString, 拷贝粘贴字符串位置写 ** R a n d o m S t r i n g ( 16 C f e n g 123 ) ∗ ∗ , 在前面的 i n p u t 中输入数据,点击 G e n e r a t e 就可以随机生成,赋值生成的函数,就可以生成,也就是上面的 {_RandomString(16Cfeng123)}**, 在前面的input中输入数据, 点击Generate就可以随机生成,赋值生成的函数,就可以生成, 也就是上面的 RandomString(16Cfeng123)∗∗,在前面的input中输入数据,点击Generate就可以随机生成,赋值生成的函数,就可以生成,也就是上面的{XXX} ---- 引入变量
JMeter是可以读取外部的CSV文件的,直接新建一个CSV文件, 在线程组中添加CSV配置原件

使用变量主要的是指定变量,JMeter函数input中生成,而这里的CSV文件,需要在这里配置CSV文件中数据的变量的名称,在HTTP请求脚本中通过${}引用
在JSON计划中添加JSON提取器,编写JSON提取器的相应规则,在Names of created variables后面配置HTTP请求中编写的变量名称, 在JSON path expressions 中填写JSON的value映射 eg: name --> $.name
JMeter是支持选择语言的 ---- Options -》 ChooseLanguage —> Chinese(Simplified),修改语言
首先直接新建一个测试计划,命名之后; 在测试计划下面新建线程组,设置线程数、 Rame-up时间; 这里Cfeng直接设置1s内执行1000个线程 ---- 这样才符合高并发要求
之后就是在线程组下面添加HTTP请求取样器

HTTP取样器的使用和PostMan没有太大的差别; 这里应该是在该请求下添加查看结果树和CSV文件设置
当时Cfegn直接放在线程组下面,因为只是测试一个接口,所以影响不大,配置完成之后,点击运行即可

可以看到这里就成功发起1000次请求,因为Cfeng让这些请求访问的是缓存并且加上了分布式🔒,所以最终结果符合预期,只有10个人抢到了红包
测试的之前的结果,1s发起了1000次请求【来自15个用户左右】,一个用户点击多次,因为秒杀,实际一个用户会点击很多次,加了分布式锁再配合原子命令实现实现类抢红包的操作,可以看到这里能够抗住压力,是因为操作的都是在缓存中,总共的写入数据库的操作一共就10次,并且设置了为异步方式, 不需要每次都访问数据库
1s内所有的红包都抢光了,所以最后日志打印读取total的数据都是0,因为不同的用户的进程都同时进入了Service
2022-09-13 22:50:25.780 WARN 22864 --- [ task-7] c.a.druid.pool.DruidAbstractDataSource : discard long time none received connection. , jdbcUrl : jdbc:mysql://localhost:3306/db_middleware?useUnicode=true&characterEncoding=utf-8&useSSL=true&servertimezone=GMT%2B8, version : 1.2.8, lastPacketReceivedIdleMillis : 113460
2022-09-13 22:50:25.783 INFO 22864 --- [io-8081-exec-33] c.server.service.impl.RedServiceImpl : 当前用户抢到红包了:剩余红包数量:0,userId=10025 key=redis:red:packet:10011:52103535738800 金额=0.64
2022-09-13 22:50:25.783 INFO 22864 --- [io-8081-exec-20] c.server.service.impl.RedServiceImpl : 当前用户抢到红包了:剩余红包数量:0,userId=10030 key=redis:red:packet:10011:52103535738800 金额=0.31
2022-09-13 22:50:25.783 INFO 22864 --- [io-8081-exec-52] c.server.service.impl.RedServiceImpl : 当前用户抢到红包了:剩余红包数量:0,userId=10026 key=redis:red:packet:10011:52103535738800 金额=0.78
2022-09-13 22:50:25.783 INFO 22864 --- [io-8081-exec-57] c.server.service.impl.RedServiceImpl : 当前用户抢到红包了:剩余红包数量:0,userId=10011 key=redis:red:packet:10011:52103535738800 金额=1.07
2022-09-13 22:50:25.783 INFO 22864 --- [nio-8081-exec-7] c.server.service.impl.RedServiceImpl : 当前用户抢到红包了:剩余红包数量:0,userId=10015 key=redis:red:packet:10011:52103535738800 金额=1.9
2022-09-13 22:50:25.783 INFO 22864 --- [io-8081-exec-26] c.server.service.impl.RedServiceImpl : 当前用户抢到红包了:剩余红包数量:0,userId=10016 key=redis:red:packet:10011:52103535738800 金额=1.57
2022-09-13 22:50:25.783 INFO 22864 --- [io-8081-exec-53] c.server.service.impl.RedServiceImpl : 当前用户抢到红包了:剩余红包数量:0,userId=10013 key=redis:red:packet:10011:52103535738800 金额=1.06
2022-09-13 22:50:25.783 INFO 22864 --- [io-8081-exec-56] c.server.service.impl.RedServiceImpl : 当前用户抢到红包了:剩余红包数量:0,userId=10021 key=redis:red:packet:10011:52103535738800 金额=0.51
2022-09-13 22:50:25.783 INFO 22864 --- [io-8081-exec-68] c.server.service.impl.RedServiceImpl : 当前用户抢到红包了:剩余红包数量:0,userId=10020 key=redis:red:packet:10011:52103535738800 金额=0.55
2022-09-13 22:50:25.783 INFO 22864 --- [io-8081-exec-65] c.server.service.impl.RedServiceImpl : 当前用户抢到红包了:剩余红包数量:0,userId=10028 key=redis:red:packet:10011:52103535738800 金额=1.61
通过页面单击的形式,记录所有的请求信息,包括HTTP响应信息和请求头
通常使用JMeter的HTTP代理服务器录制性能测试脚本,【除此之外,还可以使用BadBoy工具仅录制,录制为jmx文件
测试计划 --> 添加 --> 非测试原件 —> HTTP代理服务器

在代理服务器中可以编写自定义的代理端口号,在目标控制器进行配置,目标控制器代表此次录制的脚本放置在哪个线程组中,配置结束,点击启动按钮即可
搭建代理服务器后,配置本地计算机的Internet属性: 增加代理服务器、刚自定义端口号

代理服务器进行请求的接口已经录制到线程组中
最开始问题的advise: