项目
博客
文档
归档
资源链接
关于我
项目
博客
文档
归档
资源链接
关于我
20| Jmeter5.X压力测试(库存扣减超发)
2024-08-08
·
·
原创
·
·
本文共 613个字,预计阅读需要 3分钟。
### 常用测试工具对 `LoadRunner`:性能稳定,压测结果及细粒度⼤,可以⾃定义脚本进⾏压测,但是太过于重⼤,功能⽐较繁多 `Apache AB(单接⼝压测最⽅便`):模拟多线程并发请求,ab命令对发出负载的计算机要求很低,既不会占⽤很多CPU,也不会占⽤太多的内存,但却会给⽬标服务器造成巨⼤的负载, 简单DDOS攻击等 `Webbench`: webbench⾸先fork出多个⼦进程,每个⼦进程都循环做web访问测试。⼦进程把访问的结果通过pipe告诉⽗进程,⽗进程做最终的统计结果。 `Jmeter`: 开源免费,功能强⼤,在互联⽹公司普遍使⽤。 压测不同的协议和应⽤ - Web - HTTP, HTTPS (Java, NodeJS, PHP,ASP.NET, …) - SOAP / REST Webservices - FTP - Database via JDBC - LDAP 轻ᰁ⽬录访问协议 - Message-oriented middleware (MOM) via JMS - Mail - SMTP(S), POP3(S) and IMAP(S) - TCP等等 使⽤场景及优点 - 功能测试 - 压⼒测试 - 分布式压⼒测试 - 纯java开发 - 上⼿容易,⾼性能 - 提供测试数据分析 - 各种报表数据图形展示 压测⼯具本地快速安装Jmeter5.x - 要JDK⾥⾯的 keytool⼯具 - 快速下载 https://jmeter.apache.org/download_jmeter.cgi - ⽂档地址:http://jmeter.apache.org/usermanual/get-started.html ### 目录文件讲解 - `bin`: 核⼼可执⾏⽂件,包含配置 - `jmeter.bat`: windows启动⽂件(window系统⼀定要配置显示⽂件拓展名) - `jmeter`: mac或者linux启动⽂件 - `jmeter-server`:mac或者Liunx分布式压测使⽤的启动⽂件 - `jmeter-server.bat`:window分布式压测使⽤的启动⽂件 - `jmeter.properties`: 核⼼配置⽂件 - `extras`:插件拓展的包 - `lib`: 核⼼的依赖包 `汉化`:控制台修改 `menu -> options -> choose language` 配置⽂件修改 - bin⽬录 -> `jmeter.properties` - 默认 #language=en - 改为` language=zh_CN` ### 组件的线程组和Sampler 添加->threads->线程组(控制总体并发) - `线程数`:虚拟⽤户数。⼀个虚拟⽤户占⽤⼀个进程或线程 - `准备时⻓`(Ramp-Up Period(in seconds)):全部线程启动的时⻓,⽐如100个线程,20秒,则表示20秒内 100个线程都要启动完成,每秒启动5个线程 - `循环次数`:每个线程发送的次数,假如值为5,100个线程,则会发送500次请求,可以勾选永远循环 线程组->添加-> Sampler(采样器) -> Http (⼀个线程组下⾯可以增加⼏个Sampler) - 名称:采样器名称 - 注释:对这个采样器的描述 - web服务器: - 默认协议是http - 默认端⼝是80 - 服务器名称或IP :请求的⽬标服务器名称或IP地址 - 路径:服务器URL 查看测试结果: - 线程组->添加->监听器->察看结果树 - 线程组->添加->监听器->聚合报告 ### 压测结果与报告分析、扣减为负超发问题 优惠券列表接⼝压测 新增聚合报告:线程组->添加->监听器->聚合报告(Aggregate Report) - `lable`: sampler的名称 - `Samples`: ⼀共发出去多少请求,例如10个⽤户,循环10次,则是 100 - `Average`: 平均响应时间 - `Median`: 中位数,也就是 50% ⽤户的响应时间 90% Line : 90% ⽤户的响应不会超过该时间 (90% of the samples took no more than this time. The remaining samples at least as long as this) - `95% Line` : 95% ⽤户的响应不会超过该时间 - `99% Line` : 99% ⽤户的响应不会超过该时间 - `min` : 最⼩响应时间 - `max `: 最⼤响应时间 - `Error%`:错误的请求的数ᰁ/请求的总数 - `Throughput`: 吞吐ᰁ——默认情况下表示每秒完成的请求数(Request per Second) 可类⽐为qps、tps - `KB/Sec`: 每秒接收数据ᰁ 优惠券扣减sql:`update coupon set stock=stock-1 where id = #{couponId}` 存在的问题:`扣减存储为负数,超发优惠券`,会造成资损。 ### 高并发下正确的库存扣减 不谈秒杀设计,不谈使⽤`队列(限流、队列、异步)`等使`请求串⾏化`。 ⽤`锁来保证数据正确`,防⽌超发导致库存是负数: - 同步代码块`synchronized ,lock`,分布式不适合。 ```java public synchronized void reduceCouponStock(long couponId ,Integer num){ //业务逻辑 } //问题:synchronized 作⽤范围是单个jvm实例, 如果做了集群分布式等,就失效了,且单机JVM加锁后就是串⾏等待问题 ``` - 分布式锁 `zookeeper,redis`,可行,但`过于笨重,性能有所下降` - 直接数据库更新扣减。 ```sql update coupon set stock=stock - #{num} where id = #{couponId} and stock>0 //测试如果num⼤于已有库存,则会变负数 update coupon set stock=stock - #{num} where id = #{couponId} and (stock - #{num})>=0 或者 update coupon set stock=stock - #{num} where id = #{couponId} and stock >= #{num} ``` `如果扣减最多1个,则直接使⽤这种就⾏`。 ```sql update coupon set stock=stock-1 where id = #{couponId} and stock>0 ``` **延伸**: `update coupon set stock=stock-1 where id = #{couponId} and stock = #{oldStock}` 问题:`扣减库存,如果别⼈补充库存,就存在ABA问题`,看业务是否有这个限制,当期采⽤上⾯那种。 > ⽐如: > > - C线程查出来是10个 > - A线程扣减1个,剩9个 > - B线程更新了库存,变回10个 > - C更新的时候发现还是10个,则更新成功, 所以避免这个问题,要求不管谁修改了库存,⼀定要`加个version递增版本号`z 最终的sql: ```sql update coupon set stock=stock-1,version=version+1 where id = #{couponId} and stock>0 and versoin=#{oldVersion} ``` ⾼并发库存扣减超卖问题,很多⼈加了乐观锁版本号去解决,那下⾯三种有什么区别,分别适合哪些场景使⽤: ```sql 1)update product set stock=stock-1 where id = 1 and stock>0 2)update product set stock=stock-1 where stock=#{原先查询的库存} and id = 1 and stock>0 3)update product set stock=stock-1,versioin =version+1 where id = 1 and stock>0 and version=#{原先查询的版本号} ``` 核⼼是解决超卖的问题,就是防⽌库存为负数。