谷粒商城笔记+踩坑(11)——性能压测和调优,JMeter压力测试+jvisualvm监控性能+资源动静分离+修改堆内存

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
性能测试 PTS,5000VUM额度
简介: 使用JMeter对项目各个接口进行压力测试,并对前端进行动静分离优化,优化三级分类查询接口的性能

 导航:

谷粒商城笔记+踩坑汇总篇

Java笔记汇总:

【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析-CSDN博客

目录

1.JMeter压力测试

1.1 压力测试的性能指标

1.2 JMeter 安装

1.3 JMeter 中文配置

1.4 JMeter 压测示例

1.4.1 添加线程组

1.4.2 添加 HTTP 请求

1.4.3 添加监听器

1.4.4 启动压测

1.4.5 查看分析结果

1.5 错误解决JMeter Address Already in use ,Windows端口访问机制

2. 性能监控

2.1 回顾jvm内存模型

2.2 回顾堆

2.2.0概念

2.2.1垃圾回收流程

2.3 使用jconsole监控本地和远程应用

2.4 jvisualvm(比jconsole强大)

2.4.0 启动jvisualvm

2.4.1 jvisualvm 能干什么

2.4.2 安装Visual GC插件

2.5 监控指标

2.5.1 中间件监控指标

2.5.2 数据库监控指标

3. 压力测试和优化

3.1 压测

3.1.1 压测nginx

3.1.2 压测网关

3.1.3 压测无业务服务

3.1.4 压测首页一级菜单渲染(thymeleaf 关闭缓存)

3.1.5 压测首页一级菜单渲染(thymeleaf 开启缓存)

3.1.6 压测首页一级菜单渲染(开缓存,数据库加索引,关日志)

3.1.7 压测三级分类数据获取

3.1.8 压测三级分类数据获取(加索引)

3.1.9 压测三级分类数据获取(优化业务)

3.1.10 三级分类数据获取(使用redis作为缓存)

3.1.11 首页全量数据获取(包括静态资源)

3.1.12 Nginx+Gateway

3.1.13 Gateway+简单服务

3.1.14 结论,中间件对性能的影响

3.2 优化,动静分离

3.2.1 什么要动静分离

3.2.2 静态资源存到Nginx里

3.2.3 templates里文件静态资源路径前“static”

3.2.4 在nginx配置静态资源的路径映射

3.2.5 测试

3.3 优化,模拟内存崩溃宕机问题

3.4 优化三级分类数据获取

3.4.1 当前问题

3.4.2 将数据库的多次查询变为一次


1.JMeter压力测试

压力测试考察当前软硬件环境下系统所能承受的最大负荷并帮助找出系统瓶颈所在。 压测都是为了系统在线上的处理能力和稳定性维持在一个标准范围内, 做到心中有数。

使用压力测试, 我们有希望找到很多种用其他测试方法更难发现的错误。 有两种错误类型是:内存泄漏并发与同步问题

内存泄漏:内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

并发与同步:

有效的压力测试系统将应用以下这些关键条件:重复并发量级随机变化

1.1 压力测试的性能指标

  • 响应时间(Response Time:RT)
    响应时间指用户从客户端发起一个请求开始,到客户端接收到从服务器端返回的响应结束,整个过程所耗费的时间。响应时间越少越好。
  • HPS(Hits Per Second):每秒点击次数,单位是次/秒。【不是特别重要】
  • TPS(Transaction per Second):系统每秒处理交易数,单位是笔/秒。
  • Qps(Query per Second):系统每秒处理查询次数,单位是次/秒。
    对于互联网业务中,如果某些业务有且仅有一个请求连接,那么TPS=QPS=HPS,一般情况下用 TPS来衡量整个业务流程,用QPS来衡量接口查询次数,用HPS来表示对服务器单击请求。
  • 无论TPS、QPS、HPS,此指标是衡量系统处理能力非常重要的指标,越大越好,根据经
    验,一般情况下:
    金融行业:1000TPS~5000OTPS,不包括互联网化的活动
    保险行业:100TPS~10000OTPS,不包括互联网化的活动
    制造行业:10TPS~5000TPS
    互联网电子商务:1000OTPS~1000000TPS
    互联网中型网站:1000TPS~50000TPS
    互联网小型网站:50OTPS~10000TPS
  • 最大响应时间(MaxResponse Time)指用户发出请求或者指令到系统做出反应(响应)的最大时间。
  • 最少响应时间(Mininum ResponseTime)指用户发出请求或者指令到系统做出反应(响应)的最少时间。
  • 90%响应时间(90%Response Time)是指所有用户的响应时间进行排序,第90%的响应时间。
  • 从外部看,性能测试主要关注如下三个指标
    吞吐量:每秒钟系统能够处理的请求数、任务数。
    响应时间:服务处理一个请求或一个任务的耗时。
    错误率。一批请求中结果出错的请求所占比例。

1.2 JMeter 安装

JMeter下载地址

image.gif

运行批处理文件jmeter.bat

image.gif

1.3 JMeter 中文配置

image.gif

1.4 JMeter 压测示例

1.4.1 添加线程组

右键“test plan” 添加:

image.gif

image.gif

线程组参数详解:

  • 线程数: 虚拟用户数。 一个虚拟用户占用一个进程或线程。 设置多少虚拟用户数在这里也就是设置多少个线程数。
  • Ramp-Up时间: 200个线程需要多少秒内全部启动完成。 如果线程数为 10, 准备时长为 2, 那么需要 2 秒钟启动 10 个线程, 也就是每秒钟启动 5 个线程。
  • 循环次数: 每个线程发送请求的次数。勾选“永远”会一直压力测试下去。 如果线程数为 10, 循环次数为 100, 那么每个线程发送 100 次请求。 总请求数为 10*100=1000 。 如果勾选了“永远”, 那么所有线程会一直发送请求, 一到选择停止运行脚本。
  • Delay Thread creation until needed: 直到需要时延迟线程的创建。
  • 调度器: 设置线程组启动的开始时间和结束时间(配置调度器时, 需要勾选循环次数为永远)
  • 持续时间(秒) : 测试持续时间, 会覆盖结束时间
  • 启动延迟(秒) : 测试延迟启动时间, 会覆盖启动时间
  • 启动时间: 测试启动时间, 启动延迟会覆盖它。 当启动时间已过, 手动只需测试时当前时间也会覆盖它。
  • 结束时间: 测试结束时间, 持续时间会覆盖它。

1.4.2 添加 HTTP 请求

image.gif

image.gif

1.4.3 添加监听器

image.gif

查看结果树:

image.gif

结果树可以查看到每次请求成功和失败情况,响应情况。

  • 汇总报告

image.gif

样本:发送请求数。 样本数=线程数*循环次数

平均值:平均响应时间。

中位数:所有样本响应时间的中位数。

3.聚合报告

image.gif

1.4.4 启动压测

启动:

image.gif

是否保存这个测试计划:

image.gif

image.gif

1.4.5 查看分析结果

结果树: 查看每个请求路径、方式、响应结果

image.gif

汇总报告: 20000个请求(样本),平均69ms内完成,最快请求67ms,最慢请求2027ms,标准偏差越大说明越不稳定,异常0%也就是没发生异常,吞吐量(单位时间传输的数据量)是每秒1986.7KB,每秒能接收5622KB数据、发送228KB数据

image.gif

聚合报告:20000个样本,平均69ms内完成,中位数是52ms内完成,TP90(90%请求在多少ms内完成)是105ms

image.gif

汇总图:先勾选显示的数据,然后点击“图形”显示图标查看汇总图

image.gif

image.gif 清空全部报告:

image.gif

结果分析 :

  • 有错误率同开发确认, 确定是否允许错误的发生或者错误率允许在多大的范围内;
  • Throughput 吞吐量每秒请求的数大于并发数, 则可以慢慢的往上面增加; 若在压测的机器性能很好的情况下, 出现吞吐量小于并发数, 说明并发数不能再增加了, 可以慢慢的往下减, 找到最佳的并发数;
  • 压测结束, 登陆相应的 web 服务器查看 CPU 等性能指标, 进行数据的分析;
  • 最大的 tps:不断的增加并发数, 加到 tps 达到一定值开始出现下降, 那么那个值就是
    最大的 tps。
  • 最大的并发数: 最大的并发数和最大的 tps 是不同的概率, 一般不断增加并发数, 达到一个值后, 服务器出现请求超时, 则可认为该值为最大的并发数。
  • 压测过程出现性能瓶颈, 若压力机任务管理器查看到的 cpu、 网络和 cpu 都正常, 未达 到 90%以上, 则可以说明服务器有问题, 压力机没有问题。
  • 影响性能考虑点包括:数据库、 应用程序、 中间件(tomact、 Nginx) 、 网络和操作系统等方面
  • 首先考虑自己的应用属于 CPU 密集型(以空间换时间)还是 IO 密集型(以时间换空间)

1.5 错误解决JMeter Address Already in use ,Windows端口访问机制

image.gif

出现原因

windows 本身提供的端口访问机制的问题。

Windows 提供给 TCP/IP 链接的端口为 1024-5000, 并且要四分钟来循环回收他们。 就导致我们在短时间内跑大量的请求时将端口占满了

解决思路

扩大提供给 TCP/IP 链接的端口

缩短循环回收时间

计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

  • 右击 parameters, 添加一个新的 DWORD, 名字为 MaxUserPort

image.gif

  • 然后双击 MaxUserPort, 输入数值数据为 65534, 基数选择十进制(如果是分布式运行的话, 控制机器和负载机器都需要这样操作哦)

image.gif

  • 右击 parameters, 添加一个新的 DWORD, 名字为 TCPTimedWaitDelay

image.gif

  • 重启系统并测试

2. 性能监控

  • 影响性能考虑点包括:数据库、 应用程序、 中间件(tomact、 Nginx) 、 网络和操作系统等方面
  • 首先考虑自己的应用属于 CPU 密集型(以空间换时间)还是 IO 密集型(以时间换空间)

2.1 回顾jvm内存模型

Java源文件编译成.class字节码文件 ,.class字节码文件被JVM的类装载器装载到JVM里,所有数据都在“运行时数据区”。性能优化主要是优化“运行时数据区”中的“堆”

当数据都在“运行时数据区”后,JVM的执行引擎负责执行,在虚拟机栈里进行方法的调用,入栈、出栈等操作。本地方法栈调用本地库,程序计数器记录程序走到哪一行。

image.gif

  • 程序计数器 Program Counter Register:
  • 记录的是正在执行的虚拟机字节码指令的地址,
  • 此内存区域是唯一一个在JAVA虚拟机规范中没有规定任何OutOfMemoryError的区域
  • 虚拟机: VM Stack
  • 描述的是 JAVA 方法执行的内存模型, 每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表, 操作数栈, 动态链接, 方法接口等信息
  •  局部变量表存储了编译期可知的各种基本数据类型、 对象引用
  •  线程请求的栈深度不够会报 StackOverflowError 异常
  •  栈动态扩展的容量不够会报 OutOfMemoryError 异常
  •  虚拟机栈是线程隔离的, 即每个线程都有自己独立的虚拟机栈
  • 本地方法: Native Stack
  • 本地方法栈类似于虚拟机栈, 只不过本地方法栈使用的是本地方法
  • 堆: Heap
  • 几乎所有的对象实例都在堆上分配内存

详细模型

image.gif

2.2 回顾堆

2.2.0概念

所有的对象实例以及数组都在堆上分配堆是垃圾收集器管理的主要区域, 也被称为“GC堆” ; 也是我们优化最多考虑的地方。

堆可以细分为:

  • 新生代
  • Eden 空间
  • From Survivor 空间
  • To Survivor 空间
  • 老年代
  • 永久代/元空间
  • Java8 以前永久代, 受 jvm 管理, java8 以后元空间, 直接使用物理内存。 因此,默认情况下, 元空间的大小仅受本地内存限制。

2.2.1垃圾回收流程

image.gif

创建对象放到堆内存的流程:

 

1.首先,任何新对象都分配到 eden 空间。两个幸存者空间开始时都是空的。

2.当 eden 空间填满时,将触发一个Minor GC(年轻代的垃圾回收),删除所有未引用的对象,大对象(需要大量连续内存空间的Java对象,如那种很长的字符串)直接进入老年代。

3.所有被引用的对象作为存活对象,将移动到第一个幸存者空间S0,并标记年龄为1,即经历过一次Minor GC。之后每经过一次Minor GC,年龄+1。

4.当 eden 空间再次被填满时,会执行第二次Minor GC,将Eden和S0区中所有垃圾对象清除,并将存活对象复制到S1并年龄加1,此时S0变为空。

5.如此反复在S0和S1之间切换几次之后,还存活的年龄等于15的对象在下一次Minor GC时将放到老年代中。

6.当老年代满了时会触发FullGC(全GC),Full GC 清理整个堆 – 包括年轻代和老年代。

7.Major GC是老年代的垃圾回收,经常会伴随至少一次Minor GC,比Minor GC慢10倍以上。

 

Minor GC:清理年轻代空间(包括 Eden 和 Survivor 区域),释放在Eden中所有不活跃的对象,释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区。

Survivor区:Survivor区被用来作为Eden及老年代的中间交换区域,当老年代空间足够时,Survivor区的对象会被移到老年代,否则会被保留在Survivor区。

Major GC:清理老年代空间,当老年代空间不够时,JVM会在老年代进行major gc。

Full GC:清理整个堆空间,包括年轻代和老年代空间。Full GC比Minor GC慢十倍,应该尽量避免。

旧对象:

1、放到幸存者区survivor,如果放得下放在to区【然后from 和 to转变身份】【超过阈值15放到老年代】

2、如果survivor放不下判断老年代是否放得下,放不下执行FullGC

3、如果老年代放不下OOM异常

image.gif

详细流程

image.gif

2.3 使用jconsole监控本地和远程应用

Jdk 的两个小工具 jconsole、 jvisualvm(升级版的 jconsole) ;通过命令行启动, 可监控本地和远程应用。 远程应用需要配置

直接cmd输入jconsole

进入jconsole页面选择gulimall商品模块:

image.gif

首页情况

image.gif

内存情况

image.gif

2.4 jvisualvm(比jconsole强大)

2.4.0 启动jvisualvm

image.gif

连接进程:

image.gif

2.4.1 jvisualvm 能干什么

监控内存泄露, 跟踪垃圾回收, 执行时内存、 cpu 分析, 线程分析…

image.gif

image.gif

线程状态:

  • 运行: 正在运行的
  • 休眠: sleep
  • 等待: wait
  • 驻留: 线程池里面的空闲线程
  • 监视: 阻塞的线程, 正在等待锁

2.4.2 安装Visual GC插件

  1. cmd 启动jvisualvm,点击“工具”-“插件”,点击“检查最新版本”看是否报错
  2. 不保存就安装 Visual GC
  3. 安装后重启jvisualvm

image.gif

503报错,插件安装失败问题:

原因:

  1. 可能是因为更新链接配置的版本不对
  2. 自己有代理的话一定要关闭

image.gif

  • 查看自己jdk版本

我的版本是281xxx

image.gif

找到对应的版本复制链接

image.gif

  • 修改配置的链接

image.gif

安装插件后重启jvisualvm效果如下:

可以看见实时的整个GC过程。

image.gif

2.5 监控指标

2.5.1 中间件监控指标

image.gif

  • 当前正在运行的线程数不能超过设定的最大值。 一般情况下系统性能较好的情况下, 线程数最小值设置 50 和最大值设置 200 比较合适。
  • 当前运行的 JDBC 连接数不能超过设定的最大值。 一般情况下系统性能较好的情况下,JDBC 最小值设置 50 和最大值设置 200 比较合适。
  • G C 频率不能频繁, 特别是 FULL GC 更不能频繁, 一般情况下系统性能较好的情况下,JVM 最小堆大小和最大堆大小分别设置 1024M 比较合适。

2.5.2 数据库监控指标

image.gif

  • SQL 耗时越小越好, 一般情况下微秒级别。
  • 命中率越高越好, 一般情况下不能低于 95%。
  • 锁等待次数越低越好, 等待时间越短越好。

3. 压力测试和优化

3.1 压测

3.1.1 压测nginx

动态查看doker各个容器的状态

#动态查看doker各个容器的状态
docker stats

image.gif

Nginx未压测状态:

image.gif

mem usage是内存使用量

net i/o网络数据传输

JMeter 压力测试:

image.gif 添加取样器:访问首页

image.gif

50个线程压测后状态,可以看见Nginx主要浪费CPU:

image.gif

得出结论nginx是CPU 密集型

压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944

3.1.2 压测网关

JMeter添加请求后运行:

image.gif

jvisualvm监测网关

image.gif

压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944
Gateway 50 10367 8 31

对cpu与内存进行监控

得出结论网关也是cup密集型

对gc进行监控

发现网关的不断在进行轻gc,偶尔执行重gc

虽然轻gc的次数远远大于重gc的次数,但是所用时间并没有多多少

得出结论:

可以适当调大内存区的大小,避免gc次数太多而造成性能的下降

image.gif

3.1.3 压测无业务服务

添加无业务服务:

gulimall-product/src/main/java/site/zhourui/gulimall/product/web/IndexController.java

//压测简单服务(无任何业务逻辑):
  @ResponseBody
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }

image.gif

image.gif

压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944
Gateway 50 10367 8 31
简单服务 50 11341 8 17

3.1.4 压测首页一级菜单渲染(thymeleaf 关闭缓存)

image.gif

结论:

压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944
Gateway 50 10367 8 31
简单服务 50 11341 8 17
首页一级菜单渲染 50 270(db,thymeleaf) 267 365

3.1.5 压测首页一级菜单渲染(thymeleaf 开启缓存)

thymeleaf开启缓存后吞吐量有一定的提升

压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944
Gateway 50 10367 8 31
简单服务 50 11341 8 17
首页一级菜单渲染 50 270(db,thymeleaf) 267 365
首页渲染(开缓存) 50 290 251 365

3.1.6 压测首页一级菜单渲染(开缓存,数据库加索引,关日志)

  • 开启缓存
thymeleaf:
    cache: true
  • image.gif
  • 对pms_category表的parent_cid加上索引

image.gif

  • 关日志
logging:
  level:
    site.zhourui.gulimall: error

image.gif

数据库的优化(加索引)对性能的提升还是挺大的

压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944
Gateway 50 10367 8 31
简单服务 50 11341 8 17
首页一级菜单渲染 50 270(db,thymeleaf) 267 365
首页渲染(开缓存) 50 290 251 365
首页渲染(开缓存、 优化数据库、 关日 志) 50 700 105 183

3.1.7 压测三级分类数据获取

主要是数据库导致的吞吐量降低,太慢了

localhost:10001/index/catalog.json

image.gif

压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944
Gateway 50 10367 8 31
简单服务 50 11341 8 17
首页一级菜单渲染 50 270(db,thymeleaf) 267 365
首页渲染(开缓存) 50 290 251 365
首页渲染(开缓存、 优化数据库、 关日 志) 50 700 105 183
三级分类数据获取 50 2(db)

3.1.8 压测三级分类数据获取(加索引)

对pms_category表的parent_cid加上索引

image.gif

吞吐量有一定的提升

压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944
Gateway 50 10367 8 31
简单服务 50 11341 8 17
首页一级菜单渲染 50 270(db,thymeleaf) 267 365
首页渲染(开缓存) 50 290 251 365
首页渲染(开缓存、 优化数据库、 关日 志) 50 700 105 183
三级分类数据获取 50 2(db)
三级分类数据获取(加索引) 50 8

3.1.9 压测三级分类数据获取(优化业务)

1)、优化业务逻辑:

1、一次性查询出来

2、将下面查库抽取为方法,不是真的查库baseMapper.selectList(new QueryWrapper().eq(“parent_cid”, level1.getCatId()));抽取为一个方法

将第一次查询的数据存起来,封装一个方法查询这个数据,就不会重复查询数据库

idea抽取方法

选中右键:refacto=》extract=》Method

优化业务后吞吐量有了质的飞越,说明业务对性能的影响也挺大的

压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944
Gateway 50 10367 8 31
简单服务 50 11341 8 17
首页一级菜单渲染 50 270(db,thymeleaf) 267 365
首页渲染(开缓存) 50 290 251 365
首页渲染(开缓存、 优化数据库、 关日 志) 50 700 105 183
三级分类数据获取 50 2(db)
三级分类数据获取(加索引) 50 8
三级分类( 优化业 务) 50 111 571 896

3.1.10 三级分类数据获取(使用redis作为缓存)

吞吐量也有比较明显的提升

压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944
Gateway 50 10367 8 31
简单服务 50 11341 8 17
首页一级菜单渲染 50 270(db,thymeleaf) 267 365
首页渲染(开缓存) 50 290 251 365
首页渲染(开缓存、 优化数据库、 关日 志) 50 700 105 183
三级分类数据获取 50 2(db)
三级分类数据获取(加索引) 50 8
三级分类( 优化业 务) 50 111 571 896
三 级 分 类 ( 使 用 redis 作为缓存) 50 411 153 217

3.1.11 首页全量数据获取(包括静态资源)

之前的压测都没有导入静态资源

压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944
Gateway 50 10367 8 31
简单服务 50 11341 8 17
首页一级菜单渲染 50 270(db,thymeleaf) 267 365
首页渲染(开缓存) 50 290 251 365
首页渲染(开缓存、 优化数据库、 关日 志) 50 700 105 183
三级分类数据获取 50 2(db)
三级分类数据获取(加索引) 50 8
三级分类( 优化业 务) 50 111 571 896
三 级 分 类 ( 使 用 redis 作为缓存) 50 411 153 217
首页全量数据获取 50 7(静态资源)

3.1.12 Nginx+Gateway

。。

3.1.13 Gateway+简单服务

网关yml暂时添加hello路径便与测试:

image.gif

此时访问http://localhost:88/hello就是跳过Nginx,访问网关和商品服务。

image.gif

image.gif

压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944
Gateway 50 10367 8 31
简单服务 50 11341 8 17
首页一级菜单渲染 50 270(db,thymeleaf) 267 365
首页渲染(开缓存) 50 290 251 365
首页渲染(开缓存、 优化数据库、 关日 志) 50 700 105 183
三级分类数据获取 50 2(db)
三级分类数据获取(加索引) 50 8
三级分类( 优化业 务) 50 111 571 896
三 级 分 类 ( 使 用 redis 作为缓存) 50 411 153 217
首页全量数据获取 50 7(静态资源)
Nginx+Gateway 50
Gateway+简单服务 50 3124 30 125

3.1.14 结论,中间件对性能的影响

  • SQL 耗时越小越好, 一般情况下微秒级别。
  • 命中率越高越好, 一般情况下不能低于 95%。
  • 锁等待次数越低越好, 等待时间越短越好。
压测内容 压测线程数 吞吐量/s 90%响应时间 99%响应时间
Nginx 50 2335 11 944
Gateway 50 10367 8 31
简单服务 50 11341 8 17
首页一级菜单渲染 50 270(db,thymeleaf) 267 365
首页渲染(开缓存) 50 290 251 365
首页渲染(开缓存、 优化数据库、 关日 志) 50 700 105 183
三级分类数据获取 50 2(db)
三级分类数据获取(加索引) 50 8
三级分类( 优化业 务) 50 111 571 896
三 级 分 类 ( 使 用 redis 作为缓存) 50 411 153 217
首页全量数据获取 50 7(静态资源)
Nginx+Gateway 50
Gateway+简单服务 50 3124 30 125
全链路简单服务 50 800 88 310
  • 中间件越多, 性能损失越大, 大多都损失在网络交互了;
  • 业务期间需要考虑的问题:
  • 数据库(MySQL 优化)
  • 模板的渲染速度(开发时关闭缓存,上线后一定要缓存)
  • 静态资源

3.2 优化,动静分离

3.2.1 什么要动静分离

image.gif

为什么要进行动静分离?

未分离的项目静态资源放在后端,无论是动态请求还是静态请求都会来到后台,这极大的损耗了后台Tomcat性能(大部分性能都用来处理静态请求)

动静分离后,后台只会处理动态请求,而静态资源直接由nginx返回。

3.2.2 静态资源存到Nginx里

1.在nginx的html目录下新建一个static目录用来存放静态资源

mkdir /mydata/nginx/html/static
cd /mydata/nginx/html/static

image.gif

2.将gulimall-product的静态资源复制到该目录,并将本地静态资源删除

image.gif

3.2.3 templates里文件静态资源路径前“static”

开发期间关掉thymeleaf缓存:

商品模块的yml里

image.gif

gulimall-product/src/main/resources/templates/index.html

将原来的index/xxx路径修改为/static/index/xxx

image.gif

3.2.4 在nginx配置静态资源的路径映射

vim /mydata/nginx/conf/conf.d/gulimall.conf

image.gif

配置如下内容

#监听gulimall.com:80/static
location /static {
    root  /usr/share/nginx/html;       #资源在这个文件夹下匹配
}

image.gif

注意:静态路径要配置在“/” 路径上面,防止覆盖。

image.gif

3.2.5 测试

刷新后静态资源加载成功

image.gif

3.3 优化,模拟内存崩溃宕机问题

JMeter每秒200个线程:

image.gif

让老生代内存饱满:

image.gif

发现线上服务崩溃:

image.gif

堆内存溢出,线上应用内存崩溃宕机

image.gif

原因:

服务分配的内存太小,导致新生代,老年代空间都满了,gc 后也没有空间

解决方案:

调大堆内存

-Xmx1024m -Xms1024m -Xmn512m

  • -Xms :初始堆大小
  • -Xmx :最大堆大小
  • -Xmn :堆中新生代初始及最大大小

image.gif

3.4 优化三级分类数据获取

3.4.1 当前问题

每次遍历一级分类列表里的元素,都要查一次数据库。

image.gif

3.4.2 将数据库的多次查询变为一次

抽取方法:

CategoryServiceImpl

image.gif

image.gif

抽取后:

image.gif

image.gif 修改抽取的方法,不用再查询数据库:

private List<CategoryEntity> getParent_cid(List<CategoryEntity> selectList,Long parentCid) {
        List<CategoryEntity> categoryEntities = selectList.stream().filter(item -> item.getParentCid().equals(parentCid)).collect(Collectors.toList());
        return categoryEntities;
    }

image.gif

测试:

image.gif

JMeter 压力测试发现性能优化很多。


相关实践学习
通过性能测试PTS对云服务器ECS进行规格选择与性能压测
本文为您介绍如何利用性能测试PTS对云服务器ECS进行规格选择与性能压测。
相关文章
|
1月前
|
测试技术 持续交付 Apache
Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
【10月更文挑战第1天】Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
111 3
|
2月前
|
测试技术 数据库 UED
Python 性能测试进阶之路:JMeter 与 Locust 的强强联合,解锁性能极限
【9月更文挑战第9天】在数字化时代,确保软件系统在高并发场景下的稳定性至关重要。Python 为此提供了丰富的性能测试工具,如 JMeter 和 Locust。JMeter 可模拟复杂请求场景,而 Locust 则能更灵活地模拟真实用户行为。结合两者优势,可全面评估系统性能并优化瓶颈。例如,在电商网站促销期间,通过 JMeter 模拟大量登录请求并用 Locust 模拟用户浏览和购物行为,可有效识别并解决性能问题,从而提升系统稳定性和用户体验。这种组合为性能测试开辟了新道路,助力应对复杂挑战。
105 2
|
4天前
|
缓存 监控 测试技术
全网最全压测指南!教你如何测试和优化系统极限性能
大家好,我是小米。本文将介绍如何在实际项目中进行性能压测和优化,包括单台服务器和集群压测、使用JMeter、监控CPU和内存使用率、优化Tomcat和数据库配置等方面的内容,帮助你在高并发场景下提升系统性能。希望这些实战经验能助你一臂之力!
15 3
|
8天前
|
测试技术 持续交付 Apache
Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
24 3
|
6天前
|
缓存 测试技术 Apache
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
18 1
|
14天前
|
缓存 监控 数据挖掘
C# 一分钟浅谈:性能测试与压力测试
【10月更文挑战第20天】本文介绍了性能测试和压力测试的基础概念、目的、方法及常见问题与解决策略。性能测试关注系统在正常条件下的响应时间和资源利用率,而压力测试则在超出正常条件的情况下测试系统的极限和潜在瓶颈。文章通过具体的C#代码示例,详细探讨了忽视预热阶段、不合理测试数据和缺乏详细监控等常见问题及其解决方案,并提供了如何避免这些问题的建议。
37 7
|
1月前
|
缓存 测试技术 Apache
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
【10月更文挑战第1天】告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
59 4
|
2月前
|
移动开发 JSON Java
Jmeter实现WebSocket协议的接口测试方法
WebSocket协议是HTML5的一种新协议,实现了浏览器与服务器之间的全双工通信。通过简单的握手动作,双方可直接传输数据。其优势包括极小的头部开销和服务器推送功能。使用JMeter进行WebSocket接口和性能测试时,需安装特定插件并配置相关参数,如服务器地址、端口号等,还可通过CSV文件实现参数化,以满足不同测试需求。
219 7
Jmeter实现WebSocket协议的接口测试方法
|
2月前
|
测试技术 持续交付 Apache
Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
【9月更文挑战第10天】随着软件应用的不断扩展,性能测试成为确保系统稳定运行的关键环节。本文通过对比Apache JMeter和Locust,探讨了如何在Python环境中利用这两款工具挖掘更多性能测试潜力。JMeter是一款成熟且功能强大的开源工具,支持多种协议,适用于各种应用的测试;而Locust则基于Python,通过简单脚本模拟HTTP请求,更适合Web应用测试。
86 3
|
3月前
|
测试技术 持续交付 Apache
深度挖掘:Python性能测试中JMeter与Locust的隐藏技能🔍
【8月更文挑战第5天】随着软件规模扩大,性能测试对系统稳定性至关重要。Apache JMeter和Locust是两大主流工具,各有千秋。本文探索它们在Python环境下的进阶用法,挖掘更多性能测试潜力。JMeter功能强大,支持多种协议,可通过命令行模式执行复杂测试计划,并与Python集成实现动态测试数据生成。Locust基于Python,通过编写简洁脚本模拟HTTP请求,支持自定义请求及与Python库深度集成。掌握这些技巧可实现高度定制化测试场景,有效识别性能瓶颈,提升应用稳定性。
126 1